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

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

public static bool IsNull(this T t) { return ReferenceEquals(t, null); } public static T NewIfNull(this T t, Func createNew) { if (t.IsNull()) { return createNew(); } return t; } public static void Ensure(this T t, Func createNew) { t = t.NewIfNull(createNew); } 

最终我想做点什么

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

但是,Ensure方法没有达到预期的效果,即如果它为null,则将foo设置为List的实例,否则基本上将其设置为自身。

如果你现在知道我可以调整Ensure方法来实现这一点我会很感激帮助。

谢谢,汤姆

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

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

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

 foo = foo ?? new List(); 

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

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

 foo = foo ?? new List(); 

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

 var list2 = list1.Ensure>(); 

但是,你不需要那个因为你可以使用?? 运营商:

 var list2 = list1 ?? new List(); 

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

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

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