C# 使用扩展:权衡利弊

C# 使用扩展:权衡利弊,c#,extension-methods,C#,Extension Methods,最近我开始思考如何清理我认为丑陋的代码。一个建议是创建一个扩展方法,该方法将执行所需的函数并返回我想要的。我的第一个想法是“太棒了!扩展有多酷…“但是经过一点思考之后,我开始重新考虑使用扩展 我主要担心的是,扩展似乎是一种自定义的“快捷方式”,这会使其他开发人员难以遵循。我知道使用扩展有助于使代码语法更易于阅读,但如何遵循幕后的声音呢 以我前面的问题代码片段为例: if (entry.Properties["something"].Value != null) attribs.somethi

最近我开始思考如何清理我认为丑陋的代码。一个建议是创建一个扩展方法,该方法将执行所需的函数并返回我想要的。我的第一个想法是“太棒了!扩展有多酷…“但是经过一点思考之后,我开始重新考虑使用扩展

我主要担心的是,扩展似乎是一种自定义的“快捷方式”,这会使其他开发人员难以遵循。我知道使用扩展有助于使代码语法更易于阅读,但如何遵循幕后的声音呢

以我前面的问题代码片段为例:

if (entry.Properties["something"].Value != null)
  attribs.something = entry.Properties["something"].Value.ToString();
现在将其替换为扩展:

public static class ObjectExtensions
{
    public static string NullSafeToString(this object obj)
    {
        return obj != null ? obj.ToString() : String.Empty;
    }
}
并使用以下语法调用:

attribs.something = entry.Properties["something"].Value.NullSafeToString();
这确实是一种方便的方法,但它真的值得另一个类对象的开销吗?如果有人想重用我的代码段但不理解扩展,会发生什么?我本可以同样轻松地使用语法,得到相同的结果:

attribs.something = (entry.Properties["something"].Value ?? string.Empty).ToString()
所以我做了一些挖掘,找到了几篇关于使用扩展的利弊的文章。对于有兴趣的用户,请查看以下链接:


我真的无法决定哪种方式更好。做我希望他们做的事情的自定义扩展,或者显示更多代码来完成相同的任务?我真的很想了解“真正的”开发人员对这个主题的看法…

[OP]这确实是一个方便的方法,但它真的值得另一个类对象的开销吗

在这种情况下不会创建额外的类对象。在幕后,扩展方法的调用与静态方法没有什么不同。扩展方法容器有一个额外的元数据条目,但这是非常小的


[OP]如果有人想重用我的代码段但不理解扩展对象,会发生什么

那么这将是教育他们的好时机:)。是的,有一种风险,即新的开发人员可能对开始使用扩展方法感到不舒服。但这并不是一个孤立的特征。我在内部和网络上看到的所有代码示例中都越来越多地使用它。对于开发人员来说,这绝对是值得学习的。我认为它不属于“希望人们知道的深奥”的范畴,我个人认为扩展方法可读性的“问题”被大大夸大了。如果你专注于让你的代码在做什么方面易于阅读,那在大多数情况下比它如何做更重要。如果开发人员希望跟踪并找出幕后实际发生的事情,他们可以随时点击实现

扩展方法的主要问题是它们的发现方法,即通过指定的命名空间而不是指定的类。但这是另一回事:)

<> P>我并不是建议你任意地使用扩展方法,但是我会认真考虑你需要多久知道一个方法中的每一个表达式是如何工作的,而不是浏览它的范围,看看它在更大范围内的作用。


编辑:您使用的术语可能会稍微误导您。没有所谓的“扩展对象”——只有“扩展方法”,它们必须存在于静态类型中。因此,您可能需要引入一个新类型,但您不会再创建任何对象。

[OP]如果有人想重用我的代码段,但不理解扩展对象,会发生什么

如果实现扩展方法的程序集不是项目中的引用,则扩展方法将不会显示在对象的intellisense中。您的代码片段也不会编译。这可能会给其他开发人员带来一些混乱

如果引用了扩展方法程序集,它将显示在intellisense中,但在对象的文档中不会提到它。这也可能会引起一些混乱


然而,正如@JaredPar所提到的,扩展方法作为一种技术被越来越多地使用,我希望大多数C#程序员都了解它们。因此,我不必太担心任何潜在的混乱。

在扩展方法中要处理的唯一严重的奇怪之处是:

  • 如果左侧(调用方法的对象)为null,则它们不必导致null引用异常。
    • 有时可能有用,但与预期相反,因此应极其谨慎地使用
  • 它们不能通过应用于它们的类/接口上的反射来访问。
    • 一般来说这不是问题,但值得记住
  • 与其他扩展方法的名称冲突涉及冗长的解析规则序列
    • 如果您愿意,顺序是:
    • 在当前模块内定义的扩展方法
    • 在当前命名空间或其任何父命名空间的数据类型内定义的扩展方法,子命名空间的优先级高于父命名空间
    • 在当前文件的任何类型导入中定义的扩展方法
    • 在当前文件的任何命名空间导入中定义的扩展方法
    • 在任何项目级类型导入中定义的扩展方法
    • 在任何项目级命名空间导入中定义的扩展方法
  • C#扩展是.Net提供的另一个“工具”,目的是帮助您更好地编写代码。它们的另一个优点是,它们处理null。虽然它们看起来非常有用,但我尝试只在某些情况下使用它们,这将真正整理我的代码,因为它们不是标准的编码方法,它们与其他类有一点不同,因为它们必须在静态类中,并且它们本身是静态的

    让我们说说他们的即时消息
    public static string union(this List<string> stringList, String seperator)
    {
       String unionString = "";
       foreach (string stringItem in stringList) {
          unionString += seperator + stringItem; }
       if (unionString != "") { 
          unionString = unionString.Substring(seperator.Length); }
       return unionString;
    }
    
    public static String toStringNullAllowed(this Object inputObject)
    {
       if (inputObject == null) { return null; }
       return inputObject.ToString();
    }
    
    public static String toXDigit(this int inputInteger, int x)
    {
       String xDigitNumber = inputInteger.ToString();
       while (xDigitNumber.Length < x) { xDigitNumber = "0" + xDigitNumber; }
       return xDigitNumber;
    }