Будет ли условный оператор разыменования полезен в C #? - PullRequest
5 голосов
/ 18 февраля 2009

В функциональных языках часто встречается монада Maybe, которая позволяет объединить несколько вызовов объекта и получить полное выражение, возвращающее 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, а не с отдельными элементами, и он оставляет вам Maybe<T> вместо 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;
    }
}

Я вижу, что это может привести к ужасным злоупотреблениям, таким как использование .. везде, чтобы избежать NullReferenceException, но, с другой стороны, при правильном использовании это может быть очень удобно в довольно многих ситуациях. Мысли?

Ответы [ 4 ]

1 голос
/ 18 февраля 2009

Цепочка нескольких вызовов на объекте заставляет меня бояться нарушения Закона Деметры . Поэтому я скептически отношусь к тому, что эта функция является хорошей идеей, по крайней мере, с точки зрения решения конкретной проблемы, которую вы используете в качестве примера.

0 голосов
/ 18 февраля 2009

Я вижу потенциальную полезность, но кроме небольшого влияния на производительность, если элементы часто равны нулю, почему бы просто не окружить блок кода блоком try..catch для исключения NullReferenceException вместо этого?

0 голосов
/ 18 февраля 2009

Я подозреваю, что комбинация методов NUllable и расширения позволила бы достичь значительной части этого.

Это, конечно, ограничит T типами значений.

(TBH Я бы предпочел увидеть поддержку кортежей в языке и исключить параметры, как это делает F #.)

Ваш код может быть упрощен, установите для val значение null, а остальные ветви исключите.

0 голосов
/ 18 февраля 2009

Это интересная идея, которую можно реализовать с помощью метода расширения. Например, что-то вроде этого (обратите внимание, просто для примера - я уверен, что это можно уточнить):

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

  return lhs;
}
...