[英]Can I force my own short-circuiting in a method call?
假设我想检查一堆对象以确保none为null:
if (obj != null &&
obj.Parameters != null &&
obj.Parameters.UserSettings != null) {
// do something with obj.Parameters.UserSettings
}
编写一个辅助函数来接受可变数量的参数并简化这种检查是一个诱人的前景:
static bool NoNulls(params object[] objects) {
for (int i = 0; i < objects.Length; i++)
if (objects[i] == null) return false;
return true;
}
然后上面的代码可能变成:
if (NoNulls(obj, obj.Parameters, obj.Parameters.UserSettings)) {
// do something
}
对? 错误。 如果obj
为null,那么当我尝试将obj.Parameters
传递给NoNulls
时,我将得到NullReferenceException
。
所以上述方法显然是错误的。 但是使用&&
运算符的if
语句可以很好地工作,因为它是短路的。 那么: 有没有办法让方法短路,以便在方法中明确引用之前不会对其参数进行求值?
嗯,这很丑,但......
static bool NoNulls(params Func<object>[] funcs) {
for (int i = 0; i < funcs.Length; i++)
if (funcs[i]() == null) return false;
return true;
}
然后用:
if (NoNulls(() => obj,
() => obj.Parameters,
() => obj.Parameters.UserSettings)) {
// do something
}
基本上,您提供委托来懒惰地评估值,而不是值本身(因为评估这些值是导致异常的原因)。
我不是说它很好 ,但它可以作为一种选择......
编辑:我认为这实际上(并且意外地)触及了Dan所追求的核心。 在执行方法本身之前,会对所有方法的参数进行求值。 有效地使用委托可以让您延迟评估,直到方法需要调用委托来检索值。
您可以编写一个接受表达式树的函数,并将该树转换为将检查空值的表单,并返回可以安全评估的Func<bool>
以确定是否存在空值。
我怀疑虽然生成的代码可能很酷,但它会让人感到困惑,而且只是写了一堆短路a != null && ab != null...
检查。 实际上,它可能不仅仅是检查所有值并捕获NullReferenceException
(不是我主张将异常处理作为控制机制流)。
这种功能的签名是这样的:
public static Func<bool> NoNulls( Expression<Func<object>> expr )
它的用法看起来像:
NoNulls( () => new { a = obj,
b = obj.Parameters,
c = obj.Parameters.UserSettings } )();
如果我有空闲时间,我会编写一个函数来执行这样的表达式树转换并更新我的帖子。 但是,我确信Jon Skeet或Mark Gravell可以用一只眼睛闭合,一只手背后写这样的功能。
我也很想看到C#实现的.?
Eric提到的运营商。 正如一个不同的埃里克(卡特曼)可能会说,那会“踢屁股”。
如果你不介意失去静态类型的安全性,你可以使用反射。 我记得,所以我只使用你的第一个短路结构。 Eric提到的功能将受到欢迎:)
我曾经多次考虑过这个问题。 Lisp具有以您提到的方式解决问题的宏,因为它们允许您自定义评估。
我也尝试使用扩展方法来解决这个问题,但没有什么比原始代码更难看。
编辑:(回复不要让我插入代码块,所以编辑我的帖子)
哎呀,没跟上这个。 对于那个很抱歉 :)
您可以使用反射来查找并通过字符串评估成员或属性。 我的朋友写的一个类的语法如下:
new ReflectionHelper(obj)["Parameters"]["UserSettings"]
它通过方法链接工作,在每个级别返回一个ReflectionHelper。 我知道NullReferenceException是该示例中的一个问题。 我只是想证明如何将评估推迟到运行时。
一个稍微接近帮助的例子:
public class Something
{
public static object ResultOrDefault(object baseObject, params string[] chainedFields)
{
// ...
}
}
同样,这种语法很糟糕。 但这表明使用字符串+反射将评估推迟到运行时。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.