“null this”是扩展方法的可接受用法吗?

本文关键字:可接受 用法 方法 扩展 null this | 更新日期: 2023-09-27 17:56:16

所以,我真的很喜欢使用扩展方法......也许有点太多了。所以,我要问我最近的享受,以确保我不会走得太远。

场景是,我们有一个传入的Guid?变量。如果变量为 null 或 Guid.Empty ,那么我们想使用不同的 Guid。因此,我编写了一个扩展方法,使其读起来像英语:

    internal static Guid OrIfEmpty(this Guid? guid, Guid other)
    {
        if (!guid.HasValue || guid.Value == Guid.Empty)
        {
            return other;
        }
        return guid.Value;
    }

这自动意味着"null this"不会引发异常。例如,这将起作用:

((Guid?)null).OrIfEmpty(other);

如果不使用扩展方法,这是不可能的,在我看来可能会产生很大的误导。但是,它是如此简洁干净!那么,你怎么看?这是可以接受的事情,还是对其他程序员来说太混乱了?

另外,我相信在其他情况下我会做这样的事情并检查this是否为 null,但这是我目前拥有的最好的示例。

注意:我并不是特别Guid?问这个业务。我询问更多关于实现的整体模式(有一个扩展方法,可以null this

“null this”是扩展方法的可接受用法吗?

如果不使用扩展方法,这是不可能的

当然是这样,只需 make 是一个常规的静态方法调用(这是所有扩展方法):

在我看来可能会产生很大的误导

我同意,因为看起来您正在null实例上调用实例方法。 情况可能会更糟:

string s = null;
string n = s.OrIfEmpty("empty");

乍一看,这看起来像是一个等待发生的明显NullReferenceException,但它可以按设计编译和工作。

由于您的问题实际上只是征求意见,因此没有一个正确答案,但我肯定会谨慎并记录扩展方法以指示this参数可以null。或者(如@quezalcoatl暗示的那样)重命名它以更明确地支持null值:

internal static Guid OrIfNullOrEmpty(this Guid? guid, Guid other)

我个人认为会有更多的开发人员更好更快地理解(所以最终意味着代码更干净):

if (!guid.HasValue || guid.Value == Guid.Empty)
{
    return other;
}

而不是:

((Guid?)null).OrIfEmpty(other);

所以这取决于你是否为自己编码,或者你写的东西可以得到其他人的支持。就我个人而言,我认为附加值不值得"怪异":)

通常,扩展方法应检查空值。毕竟,扩展方法只不过是一个静态方法,添加了一些语法糖,以便编译器可以将其视为实例方法。

例如,如果您有以下内容:

public static class MyExtensions
{
    public static IEnumerable<TSource> Frob<TSource>(this TSource source)
    {
        // do stuff here
    }
}

然后,您可以以两种不同的方式调用它:

var foo = new List<int>();
var bar = foo.Frob();  // called like an instance method
var barby = MyExtensions.Frob(foo); // called like a static method

而对于普通实例方法,您可以假设this不为 null,但不能使用扩展方法做出该假设。

我认为这没有任何问题。只要回想一下

string.IsNullOrEmptyOrWhitespace

这来自STDLIB。

一般来说,这取决于您将如何处理该空情况。如果您以正常方式使用该函数,并且该函数在这种特殊情况下表现正常 - 一切都没问题。但是,如果您的函数进入调试模式并开始重新配置系统,那么您已经越过了最小惊讶原则,这并不好

注意:正如@JeppeStigNielsen准确地指出的那样,INOEOW不是当前版本的.Net中的扩展方法。我敢肯定我有几次它作为扩展方法,但很可能它是在某些 CTP 版本上,或者可能是旧版本的 .Net 的自定义插件,它根本不存在。很抱歉造成混乱!尽管如此,"一切都与正确的命名有关"仍然成立!:)

我认为这没关系。 请注意,带有 Nullable<Guid> 的示例还不错,因为所谓的 Nullable<Guid> 类型的nullNullable<Guid>的真实和存在值,而不是"无"。

这就是为什么您也可以在这种"null"上使用实例方法,如

Guid? g = null;
g.GetValueOrDefault();  // OK; real instance method

将其与引用类型一起使用更加"奇怪":

internal static string OrIfEmpty(this string str, string other)
{
  return string.IsNullOrEmpty(str) ? other : str;
}

因为这样您就可以在"真实"空值上调用它:

string s = null;
s.OrIfEmpty("unspecified");  // OK; s is a true null reference