Вывод типа C# ("var") из '??' нуль-коалесцирующий оператор

Я прочитал много SO вопросов о нулевом слиянии ?? оператор, но ни один из них, кажется, не решает следующую конкретную проблему, которая не касается ни обнуляемости ( здесь), ни приоритета оператора ( здесь и здесь), ни особенно неявного преобразования ( здесь, здесь, здесь и здесь). Я также прочитал документы.NET (подробнее здесь) и попытался прочитать официальную спецификацию, но, к сожалению, все безрезультатно.


Так что здесь идет. Единственная разница между следующими двумя строками заключается в использовании var для вывода типа во втором, по сравнению с явным типом Random в первой, но во второй строке выдается ошибка, как показано, в то время как с первой все в порядке.

Random x = new Random() ?? (x = new Random());        // ok

var    y = new Random() ?? (y = new Random());        // CS0841
                        //  ^-------- error here

CS0841: невозможно использовать локальную переменную 'y' до ее объявления

Что именно во второй строке делает результат неопределенным?

Из хабуба, о котором я говорил выше, я узнал, что возможность левой стороны ?? оператор null вводит зависимость от определения во время выполнения фактического экземпляра типа его правой стороны. Хм, хорошо, я думаю... что бы это ни значило? Может быть, количество тревоги, как правило, о ?? Оператору на этом сайте должно было быть какое-то страшное предупреждение...

Обнуляя сейчас, я думал, что весь смысл var Ключевое слово (в отличие от dynamicбыло то, что по определению он не был подвержен таким соображениям во время выполнения.

Другими словами, даже если мы примем консервативное, но совершенно оправданное правило "никогда не заглядывать за пределы какого-либо задания" = оператор ", поэтому мы не получаем никакой полезной информации с правой стороны ??затем, основываясь только на левой стороне, общий результат должен быть "совместим с" Random, То есть результат должен быть Random или более конкретный (производный) тип; это не может быть более общим. Поэтому по определению не должен Random быть выведенным типом, для этого использования во время компиляции var?

Насколько я понимаю, развращает var с соображениями времени выполнения безоговорочно побеждает его цель. Разве это не то, что dynamic для? Итак, я думаю, вопросы:

  • Является ли оператор с нулевым слиянием единственным и / или редким исключением из моего понимания философии типизации C# static (то есть компиляции)?
  • Если да, то каковы преимущества или компромиссы между этим дизайном и тем, что здесь происходит, а именно, намеренным введением недетерминизма в систему статического вывода типа, и который он ранее не демонстрировал? не удалось dynamic были реализованы без ущерба для чистоты статической типизации?
  • Разве это не один из основных моментов строгой типизации, позволяющий обеспечить строгость проектирования во время компиляции посредством действенной обратной связи с разработчиком? Почему не могу var просто придерживайтесь политики строгого консерватизма -всегда выводя наиболее конкретный тип, который может быть выведен статически - в то же время, когда оператор с нулевым слиянием делает все, что хочет, основываясь на информации из будущего?

2 ответа

Решение

Это не соображение времени выполнения.

Тип времени компиляции переменной, объявленной с использованием var статический тип его инициализатора. Статический тип ?? Выражение является общим типом статического типа обоих операндов. Но статический тип второго операнда является статическим типом y, который не известен. Поэтому статический тип всего инициализатора неизвестен, и вывод не выполняется.

Это правда, что существуют типы, для которых инициализация будет согласованной, но их нельзя найти с помощью правил вывода C#.

Когда вы используете varтип выясняется во время компиляции. Поэтому, когда вы пишете это:

var    y = new Random() ?? (y = new Random()); 

компилятор не может определить, что yЭто тип во время компиляции и, следовательно, начинает кричать - решение, будет ли левая сторона ?? является нулевым или нет, будет определено во время выполнения.

Лучшим примером будет:

public interface IA { void Do(); }
public class A : IA { ... }
public class B : IA { ... }

A a = null;
var something = a ?? new B(); 

Какой должен быть тип something: IA, A или же B?

Другие вопросы по тегам