在函数式语言中,通常有一个Maybe
monad允许你链接对象的多个调用,并且如果链的任何部分评估,则整个表达式返回None
/ null
什么都不是,而不是典型的NullReferenceException
你通过链接一个对象可能为null的调用而进入C#。
这可以通过编写带有一些扩展方法的Maybe<T>
来实现,以允许使用查询理解在C#中进行类似的行为,这在处理带有可选元素/属性的XML时非常有用。
var val = from foo in doc.Elements("foo").FirstOrDefault().ToMaybe()
from bar in foo.Attribute("bar").ToMaybe()
select bar.Value;
但是这种语法有点笨拙且不直观,因为人们习惯于处理Linq中的序列而不是单个元素,并且最后会留下Maybe<T>
而不是T
。条件去参照运算符(例如..
)是否足以使其成为语言? e.g。
var val = doc.Elements("foo").FirstOrDefault()..Attribute("bar")..Value;
条件去引用将扩展为:
object val;
var foo = doc.Elements("foo").FirstOrDefault();
if (foo != null)
{
var bar = foo.Attribute("bar");
if (bar != null)
{
val = bar.Value;
}
else
{
val = null;
}
}
我可以看到这可能会导致可怕的滥用,例如在任何地方使用..
来避免NullReferenceException
,但另一方面,如果使用得当,它可能在很多情况下非常方便。想法?
答案 0 :(得分:1)
在对象上链接多个调用会让我害怕违反Law of Demeter。因此,我怀疑这个功能是个好主意,至少在解决您使用的具体问题方面是一个例子。
答案 1 :(得分:0)
这是一个有趣的想法,可以通过扩展方法实现。例如,这样的事情(注意,例如 - 我确信它可以改进):
public static IEnumerable<T> Maybe<T>(this IEnumerable<T> lhs, Func<IEnumerable<T>, T> rhs)
{
if (lhs != null)
{
return rhs(lhs);
}
return lhs;
}
答案 2 :(得分:0)
我怀疑NUllable和扩展方法的组合可以实现其中的很大一部分。
这会将T限制为值类型。
(TBH我宁愿在语言中看到元组支持并消除参数,如F#所做的那样。)
您可以简化代码,将val设置为null并消除其他分支。
答案 3 :(得分:-2)
我可以看到潜在的用处,但是如果元素通常为空,那么除了轻微的性能影响之外,为什么不使用try..catch块为代码块包围NullReferenceException呢?