Как ведет себя правая ассоциативная связь с оператором нулевого слияния?
оператор слияния null является ассоциативным справа, что означает выражение вида
первый?? второй трети
оценивается как
первый?? (второй трети)
Исходя из вышеизложенного правила, я думаю, что следующий перевод не является правильным.
От:
Address contact = user.ContactAddress;
if (contact == null)
{
contact = order.ShippingAddress;
if (contact == null)
{
contact = user.BillingAddress;
}
}
Для того, чтобы:
Address contact = user.ContactAddress ??
order.ShippingAddress ??
user.BillingAddress;
Вместо этого я думаю, что следующее правильно (пожалуйста, поправьте меня, если я ошибаюсь)
Address contact = (user.ContactAddress ?? order.ShippingAddress) ??
user.BillingAddress;
4 ответа
Спекуляция на самом деле противоречива.
Раздел 7.13 спецификации C# 4 гласит:
Нулевой объединяющий оператор является ассоциативным справа, что означает, что операции сгруппированы справа налево. Например, выражение вида
a ?? b ?? c
оценивается какa ?? (b ?? c)
,
С другой стороны, как было указано, 7.3.1 утверждает, что:
За исключением операторов присваивания, все бинарные операторы являются левоассоциативными
Я полностью согласен, что для простых случаев не имеет значения, как вы делаете группировку... но могут быть случаи, когда это действительно имеет значение из-за неявных преобразований типов, делающих интересные вещи, если операнды имеют разные типы.
Я рассмотрю это далее, пингую Мэдса и Эрика, и добавлю опечатку для соответствующего раздела C# в Depth (который вдохновил этот вопрос).
РЕДАКТИРОВАТЬ: Хорошо, теперь у меня есть пример, где это имеет значение... и оператор объединения нулей определенно прямо- ассоциативный, по крайней мере в компиляторе MS C# 4. Код:
using System;
public struct Foo
{
public static implicit operator Bar(Foo input)
{
Console.WriteLine("Foo to Bar");
return new Bar();
}
public static implicit operator Baz(Foo input)
{
Console.WriteLine("Foo to Baz");
return new Baz();
}
}
public struct Bar
{
public static implicit operator Baz(Bar input)
{
Console.WriteLine("Bar to Baz");
return new Baz();
}
}
public struct Baz
{
}
class Test
{
static void Main()
{
Foo? x = new Foo();
Bar? y = new Bar();
Baz? z = new Baz();
Console.WriteLine("Unbracketed:");
Baz? a = x ?? y ?? z;
Console.WriteLine("Grouped to the left:");
Baz? b = (x ?? y) ?? z;
Console.WriteLine("Grouped to the right:");
Baz? c = x ?? (y ?? z);
}
}
Выход:
Unbracketed:
Foo to Baz
Grouped to the left:
Foo to Bar
Foo to Bar
Bar to Baz
Grouped to the right:
Foo to Baz
Другими словами,
x ?? y ?? z
ведет себя так же, как
x ?? (y ?? z)
но не такой как
(x ?? y) ?? z
В настоящее время я не уверен, почему есть два преобразования из Foo в Бар при использовании (x ?? y) ?? z
- Мне нужно проверить это более тщательно...
РЕДАКТИРОВАТЬ: у меня теперь есть еще один вопрос, чтобы охватить двойное преобразование...
Ответ Джона правильный.
Просто чтобы быть ясно: ??
оператор в C# является ассоциативным справа. Я только что прошел через парсер двоичного оператора и проверил, что парсер обрабатывает ??
как право-ассоциативный.
Как указывает Джон, в спецификации говорится, что ??
оператор является ассоциативным справа, и что все бинарные операторы, кроме присваивания, являются ассоциативными слева. Поскольку спецификация противоречит самой себе, очевидно, что только один из них может быть правильным. Я буду изменять спецификации, чтобы сказать что-то вроде:
За исключением операторов простого присваивания, составного присваивания и объединения нулей, все бинарные операторы являются левоассоциативными
Я не понимаю, как это важно, оба:
(a ?? b) ?? c
а также
a ?? (b ?? c)
иметь тот же результат!
Оба работают как ожидалось и фактически идентичны, потому что выражения включают простые типы (спасибо @Jon Skeet). Это будет цепочка к первому ненулевому слева направо в ваших примерах.
Приоритет (спасибо @Ben Voigt) более интересен при объединении этого оператора с операторами другого приоритета:
value = A ?? B ? C : D ?? E;
По сути, ассоциативность по своей сути выражается через приоритет оператора или введенные пользователем подвыражения (круглые скобки).