我可以在方法调用中强制自己短路吗?
假设我想检查一堆对象以确保没有一个为空:
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
时,我将收到 NullReferenceException
到NoNulls
。
所以上述做法显然是错误的。但是使用 &&
运算符的 if
语句工作得很好,因为它是短路的。那么:是否有任何方法可以使方法短路,以便在方法内显式引用之前不会评估其参数?
Suppose I want to check a bunch of objects to make sure none is null:
if (obj != null &&
obj.Parameters != null &&
obj.Parameters.UserSettings != null) {
// do something with obj.Parameters.UserSettings
}
It is an alluring prospect to write a helper function to accept a variable number of arguments and simplify this kind of check:
static bool NoNulls(params object[] objects) {
for (int i = 0; i < objects.Length; i++)
if (objects[i] == null) return false;
return true;
}
Then the above code could become:
if (NoNulls(obj, obj.Parameters, obj.Parameters.UserSettings)) {
// do something
}
Right? Wrong. If obj
is null, then I'll get a NullReferenceException
when I try to pass obj.Parameters
to NoNulls
.
So the above approach is clearly misguided. But the if
statement using the &&
operator works just fine since it is short-circuited. So: is there any way to make a method short-circuited, so that its arguments are not evaluated until explicitly referenced within the method?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
好吧,这很难看,但是......
然后用以下方式调用它:
基本上,您提供委托来延迟评估值,而不是值本身(因为评估这些值是导致异常的原因)。
我并不是说它很好,但它是作为一种选择...
编辑:我认为,这实际上(并且意外地)触及了 Dan 所追求的核心。 所有方法的参数都会在方法本身执行之前进行评估。有效地使用委托可以让您延迟评估,直到方法需要调用委托来检索值为止。
Well, this is ugly but...
Then call it with:
Basically you're providing delegates to evaluate the values lazily, rather than the values themselves (as evaluating those values is what causes an exception).
I'm not saying it's nice, but it's there as an option...
EDIT: This actually (and accidentally) gets to the heart of what Dan was after, I think. All a method's arguments are evaluated before the method itself is executed. Using delegates effectively lets you delay that evaluation until the method needs to call the delegate to retrieve the value.
您可以编写一个函数,该函数接受表达式树并将该树转换为检查空值的形式,并返回一个可以安全评估以确定是否存在空值的
Func
我怀疑虽然生成的代码可能很酷,但它会令人困惑,并且比仅仅编写一堆短路的
a != null && 性能要差得多。 ab != null...
检查。事实上,它的性能可能比仅检查所有值并捕获 NullReferenceException 低(并不是我主张将异常处理作为控制流机制)。这样的函数的签名类似于:
它的用法类似于:
如果我有一些空闲时间,我将编写一个函数来执行这样的表达式树转换并更新我的帖子。不过,我确信乔恩·斯基特 (Jon Skeet) 或马克·格拉维尔 (Mark Gravell) 可以闭上一只眼睛、一只手放在背后编写这样的函数。
我还希望看到 C# 实现 Eric 提到的
.?
运算符。正如另一个埃里克(卡特曼)可能会说的那样,那会“很糟糕”。You could write a function that accepts an expression tree and transforms that tree into a form that will check for nulls, and return a
Func<bool>
that could be safely evaluated to determine if there is a null.I suspect that while the resulting code may be cool, it would be confusing, and much less performant than just writing a bunch of short-circuited
a != null && a.b != null...
checks. In fact, it would likely be less performant than just checking all the values and catching theNullReferenceException
(not that I advocate for exception handling as a flow of control mechanism).The signature for such a function would be something like:
and it's usage would look something like:
If I get some free time, I will write a function that does just such an expression tree transformation and update my post. However, I'm sure that Jon Skeet or Mark Gravell could write such a function with one eye closed and one hand behind their back.
I would also love to see C# implement the
.?
operator that Eric alludes to. As a different Eric (Cartman) might say, that would "kick ass".如果您不介意失去静态类型安全性,则可以使用反射。我确实介意,所以我只使用你的第一个短路结构。像埃里克提到的这样的功能将受到欢迎:)
我已经多次考虑过这个问题。 Lisp 有宏可以按照您提到的方式解决问题,因为它们允许您自定义评估。
我也尝试过使用扩展方法来解决这个问题,但没有什么比原始代码更丑陋了。
编辑:(回复不允许我插入代码块,因此编辑我的帖子)
哎呀,没有跟上这一点。抱歉:)
您可以使用反射通过字符串查找和评估成员或属性。我的一个朋友写的一个类采用如下语法:
它通过方法链接工作,在每个级别返回一个 ReflectionHelper。我知道 NullReferenceException 是该示例中的一个问题。我只是想演示如何将评估推迟到运行时。
一个稍微有用的例子:
同样,这个语法很糟糕。但这演示了使用字符串+反射将评估推迟到运行时。
You could use reflections if you don't mind losing static type safety. I do mind, so I just use your first short-circuiting construction. A feature like Eric mentioned would be welcome :)
I've thought about this problem a few times. Lisp has macros that solve the problem in the way you mentioned, since they allow you to customize your evaluation.
I have also tried using extension methods to solve this problem, but nothing there is less ugly than the original code.
Edit: (Replies don't let me insert code blocks, so editing my post)
Oops, didn't keep up on this. Sorry about that :)
You can use reflections to look up and evaluate a member or property via a string. A class one of my friends wrote took a syntax like:
It worked via method chaining, returning a ReflectionHelper at each level. I know that NullReferenceException is a problem in that example. I just wanted to demonstrate how evaluation can be deferred to runtime.
An example slightly closer to being helpful:
Again, this syntax stinks. But this demonstrates using strings + reflections to defer evaluation to runtime.