5

在函数式语言中,通常有一个Maybemonad,它允许您将多个调用链接到一个对象并让整个表达式返回None/null如果链的任何部分计算为空,而不是NullReferenceException通过链接调用在 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 中处理序列而不是单个元素,并且它在末尾留下了 aMaybe<T>而不是 a 。T条件取消引用运算符(例如..)是否足够有用以使其成为语言?例如

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;
    }
}

我可以看到这可能会导致可怕的滥用,例如..在任何地方使用来避免 a NullReferenceException,但另一方面,如果使用得当,它在很多情况下可能会非常方便。想法?

4

4 回答 4

1

将多个调用链接到一个对象让我害怕违反Demeter 法则。因此,我怀疑此功能是否是一个好主意,至少在解决您用作示例的特定问题方面。

于 2009-02-17T21:22:47.843 回答
0

这是一个有趣的想法,可以通过扩展方法来实现。例如,像这样的东西(注意,只是举例 - 我相信它可以被改进):

public static IEnumerable<T> Maybe<T>(this IEnumerable<T> lhs, Func<IEnumerable<T>, T> rhs)
{
  if (lhs != null)
  {
    return rhs(lhs);
  }

  return lhs;
}
于 2009-02-17T21:24:03.020 回答
0

我怀疑 NUllable 和扩展方法的组合可以实现其中的很大一部分。

当然,这会将 T 限制为值类型。

(TBH 我宁愿看到语言中的元组支持并消除参数,就像 F# 一样。)

您可以简化代码,将 val 设置为 null 并消除 else 分支。

于 2009-02-17T21:24:31.210 回答
-2

我可以看到潜在的用处,但除了元素经常为空时对性能的轻微影响之外,为什么不用 try..catch 块围绕代码块来代替 NullReferenceException 呢?

于 2009-02-17T21:24:58.227 回答