扩展String类与IsNullOrEmpty混淆?

Vad*_*dim 11 c# string extension-methods

每个人都知道并喜欢String.IsNullOrEmpty(yourString)方法.

我想知道如果我们将String类扩展为具有这样的方法,是否会混淆开发人员或使代码更好:

yourString.IsNullOrEmpty();
Run Code Online (Sandbox Code Playgroud)

优点:

  1. 更具可读性.
  2. 减少打字.

缺点:

  1. 可能会让人感到困惑,因为yourString 变量可能null就像你在null变量上执行方法一样 .

你怎么看?

关于myObject.IsNull()方法我们可以问同样的问题.

我会怎么写它:

public static class StringExt
{
  public static bool IsNullOrEmpty(this string text)
  {
    return string.IsNullOrEmpty(text);
  }

  public static bool IsNull(this object obj)
  {
    return obj == null;
  }
}
Run Code Online (Sandbox Code Playgroud)

小智 19

如果我没有弄错的话,这里的每个答案都谴责扩展方法可以在null实例上调用的事实,因此他们不支持相信这是一个好主意.

让我反驳他们的论点.

我不相信AT all在一个可能为null的对象上调用方法会令人困惑.事实是,我们只检查某些位置的空值,而不是100%的时间.这意味着我们进行的每个方法调用都有可能在null对象上的时间百分比.这是可以理解和接受的.如果不是,我们将在每次调用方法之前检查null.

那么,如何在null对象上发生特定的方法调用会让人感到困惑呢?看下面的代码:

var bar = foo.DoSomethingResultingInBar();
Console.Writeline(bar.ToStringOr("[null]"));
Run Code Online (Sandbox Code Playgroud)

你困惑吗?你应该.因为这里是foo的实现:

public Bar DoSomethingResultingInBar()
{
  return null; //LOL SUCKER!
}
Run Code Online (Sandbox Code Playgroud)

看到?您可以阅读代码示例而不会感到困惑.您了解到,foo可能会从该方法调用返回null,并且ToStringOr调用bar将导致NRE.你的头旋转了吗?当然不是.它理解这可能发生.现在,ToStringOr方法并不熟悉.你在这些情况下做了什么?您可以阅读该方法的文档或检查调用的代码.这里是:

public static class BarExtensions
{
  public static string ToStringOr(this bar, string whenNull)
  {
    return bar == null ? whenNull ?? "[null]" : bar.ToString();
  }
}
Run Code Online (Sandbox Code Playgroud)

混乱?当然不是.显而易见的是,开发人员想要一种检查是否bar为null 的简写方法,并为其替换非空字符串.这样做可以显着减少代码,提高可读性和代码重用率.当然,你可以通过其他方式做到这一点,但这种方式不会比任何其他方式更令人困惑.例如:

var bar = foo.DoSomethingResultingInBar();
Console.Writeline(ToStringOr(bar, "[null]"));
Run Code Online (Sandbox Code Playgroud)

当您遇到此代码时,您有什么不同于原始版本?您仍然需要检查代码,当仍为barnull 时,您仍然必须确定其行为.你仍然需要处理这种可能性.

扩展方法是否令人困惑?只有你不理解它们.而且,坦率地说,从代表到lambdas,语言的任何部分都可以这样说.


Meh*_*ari 8

我认为这个问题的根源是Jon Skeet 在他最喜欢的语言(C#)中讨厌的事情列表:C#不应该自动导入整个命名空间中的所有扩展方法.应该更明确地完成这个过程.

我个人对这个具体问题的看法是(因为我们无法对上述事实做任何事情)如果你愿意,可以使用扩展方法.我并不是说它不会令人困惑,但是关于扩展方法(可以在null引用上调用)的这个事实是一个全局性的东西,并不仅仅影响String.IsNullOrEmpty,所以C#开发人员应该熟悉它.

顺便说一句,幸运的是,Visual Studio通过(extension)IntelliSense工具提示清楚地识别扩展方法.


Jar*_*Par 6

我个人不喜欢这样做.现在扩展方法的最大问题是可发现性.你可以放弃了解特定类型中存在的所有方法,不可能查看方法调用并知道它是一种扩展方法.因此,我发现使用普通方法调用无法实现的扩展方法做任何事情都是有问题的.否则你最终会让开发人员感到困惑.

C++中存在这个问题的必然结果.在几个C++实现中,只要不触摸类型上的任何字段或虚方法,就可以在NULL指针上调用实例方法.我曾经使用过几段代码,这些代码都是故意执行此操作,并在" this==NULL" 时为方法提供不同的行为.与之合作非常令人发狂.

这并不是说我不喜欢扩展方法.恰恰相反,我喜欢它们并经常使用它们.但我认为在编写它们时应遵循两条重要规则.

  • 将实际的方法实现视为另一种静态方法,因为它实际上是.例如,对于null,抛出ArgumentException而不是NullReference异常
  • 不要让扩展方法执行普通实例方法无法执行的操作

编辑回应Mehrdad的评论

利用它的问题是我没有看到str.IsNullOrEmpty比String.IsNullOrEmpty(str)具有显着的功能优势.我看到的唯一优势是,一个人需要的打字少于另一个.关于扩展方法,通常也可以这样说.但在这种情况下,你还会改变人们对程序流程的看法.

如果更短的打字是人们真正想要的,那么IsNullOrEmpty(str)是不是更好的选择?这既是明确的,也是最短的.True C#今天不支持这样的功能.但想象一下,如果在C#我可以说

using SomeNamespace.SomeStaticClass;
Run Code Online (Sandbox Code Playgroud)

这样做的结果是SomeStaticClass上的所有方法现在都在全局命名空间中并且可用于绑定.这似乎是人们想要的,但他们将它附加到我不是很喜欢的扩展方法.


Bri*_*sio 5

我非常喜欢这种方法,因为该方法清楚地表明它正在检查对象是否为空.ThrowIfNull,IsNull,IsNullOrEmpty等.它非常易读.