我有以下扩展方法来帮助我检查和实例化对象(如果它们为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方法来实现这一目标,我将不胜感激。
谢谢,汤姆
答案 0 :(得分:10)
您需要区分对象和变量。对象永远不能为null - 变量的值可以是。你不是想改变一个关于某个对象的东西(会工作) - 你试图改变调用者变量的值。
但是,默认情况下,参数按值传递,这意味着您的扩展方法会更改参数(在方法中声明的变量),但这对调用者的<< / em>变量。通常,您可以将参数更改为ref
以实现传递引用语义,但扩展方法不能具有ref
或out
第一个参数。
正如其他人所说,使用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>());
可能会奏效,但正如其他人所说的那样,这并不是最美好的方式。