4

我有以下扩展方法来帮助我检查和实例化对象是否为空。前两个工作得很好,但它们不是很有用。

    public static bool IsNull<T>(this T t)
    {
        return ReferenceEquals(t, null);
    }

    public static T NewIfNull<T>(this T t, Func<T> createNew)
    {
        if (t.IsNull<T>())
        {
            return createNew();
        }

        return t;
    }

    public static void Ensure<T>(this T t, Func<T> createNew)
    {
        t = t.NewIfNull<T>(createNew);
    }

最终我想做类似的事情

IList<string> foo;
...
foo.Ensure<IList<string>>(() => new List<string>());

然而, Ensure 方法并没有达到预期的效果,即设置fooList<string>if 它为 null 的实例,否则基本上将其设置为自身。

如果您现在知道我可以调整 Ensure 方法来实现这一点,我将不胜感激。

谢谢,汤姆

4

4 回答 4

10

您需要区分对象变量。一个对象永远不能为空——一个变量的值可以是。您不是在尝试更改对象的某些内容(这起作用)-您是在尝试更改调用者变量的值。

但是,默认情况下,参数是按值传递的,这意味着您的扩展方法会更改参数(方法中声明的变量),但这对调用者的变量没有影响。通常您可以更改参数以ref实现按引用传递语义,但扩展方法不能有一个refout第一个参数。

正如其他人所说,使用空合并运算符 (??)是一个更好的选择。请注意,在此表达式中:

foo = foo ?? new List<string>();

除非为空,否则不会构造新列表。foo的右手操作数??不会被评估,除非它需要。

于 2012-06-10T08:53:37.627 回答
3

所以你试图复制空合并运算符?

foo = foo ?? new List<string>();
于 2012-06-10T08:51:21.997 回答
1

您的Ensure方法不起作用,因为您只是设置了一个局部引用变量 ( t) 但没有返回它。如果Ensure返回t,你可以这样做:

var list2 = list1.Ensure<List<string>>();

但是,您不需要它,因为您可以使用 ?? 操作员:

var list2 = list1 ?? new List<string>();
于 2012-06-10T08:51:44.403 回答
0

您的Ensure方法没有做任何事情,因为当不是(或)参数时,为参数分配新内容t不会改变调用者的任何内容。相反,说trefout

IList<string> foo;
...
foo = foo.NewIfNull(() => new List<string>());

可能会奏效,但正如其他人所说,这不是最漂亮的方式。

于 2012-06-10T10:41:55.850 回答