如果为null,则设置为新实例的C#扩展方法

时间:2012-06-10 08:47:21

标签: c# extension-methods

我有以下扩展方法来帮助我检查和实例化对象(如果它们为null)。前两个工作正常,但它们不是很有用。

    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方法没有达到预期的效果,如果它是null,则将foo设置为List<string>的实例,否则基本上将其设置为自身。

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

谢谢,汤姆

4 个答案:

答案 0 :(得分:10)

您需要区分对象变量。对象永远不能为null - 变量的值可以是。你不是想改变一个关于某个对象的东西(工作) - 你试图改变调用者变量的值。

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

正如其他人所说,使用null-coalescing operator (??)是一个更好的选择。请注意,在此表达式中:

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

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

答案 1 :(得分:3)

您是否尝试复制null-coalescing运算符?

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

答案 2 :(得分:1)

您的Ensure方法不起作用,因为您只是设置了一个本地引用变量(t),但没有返回它。如果Ensure返回t,您可以执行以下操作:

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

然而,你不需要那个因为你可以使用??操作者:

var list2 = list1 ?? new List<string>();

答案 3 :(得分:0)

您的Ensure方法无法执行任何操作,因为当t不是t(或{ref时,为参数out分配新内容不会改变调用方的任何内容{1}})参数。相反,说

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

可能会奏效,但正如其他人所说的那样,这并不是最美好的方式。