Является ли это ошибкой компилятора или существует определенная причина, почему оператор с нулевым условием не работает с Func
внутри общих методов?Оператор с нулевым условием не работает с Func <T> внутри общего метода
Для примера следующих не компилировать
public static T Test<T>(Func<T> func)
{
return func?.Invoke() ?? default(T);
}
Ошибка компилятор производит это CS0023 Operator '?' cannot be applied to operand of type 'T'
Я знаю, что вы можете достичь того же делает это, однако:
public static T Test<T>(Func<T> func)
{
return func != null ? func() : default(T);
}
Так почему же это запрещено?
Дальнейшая разработка Action<T>
работает, как и следовало ожидать.
public static void Test<T>(Action<T> action, T arg)
{
action?.Invoke(arg);
}
Update (2017-01-17):
После еще некоторых исследований, он делает еще меньше смысла, даже со следующим:
Допустим, у нас есть класс (Reference -типа)
public class Foo
{
public int Bar { get; set; }
}
и скажем, у нас есть Func<int>
Func<int> fun =() => 10;
следующие работы:
// This work
var nullableBar = foo?.Bar; // type of nullableBar is int?
var bar = nullableBar ?? default(int); // type of bar is int
// And this work
nullableBar = fun?.Invoke(); // ditto
bar = nullableBar ?? default(int); // ditto
что означает, по логике применяется там, то есть Func<T>
стоимостного типа с использованием null-conditional
null-coalescing
и операторы должны работать.
Однако, как только левая рука общий тип null-conditional
является родовым без каких-либо ограничений, то он не может применить ту же логику, что он должен быть в состоянии с учетом его можно применить ту же логику для обоих ценностных типов и ссылочные типы, когда типы явно применяются.
Я знаю ограничения, связанные с компиляторами, для меня просто не имеет смысла, почему он не позволяет и почему он хочет, чтобы результат был другим, независимо от того, является ли это ссылочным или стоимостным типом, рассматривая вручную применение типов даст ожидаемые результаты.
'вар х = FUNC? .Invoke()' не получится тоже. 'x' может быть нулевым или иметь некоторое значение. компилятор этого не знает. кроме того, что компилятор не знает, является ли тип «T» ссылочным или нет. обратите внимание, что 'null' недопустим для типов значений. например, вы не можете написать 'int I = null'. таким образом, вы получите ошибку. –
В двух словах, тип 'Func? .Invoke()' должен быть 'T', если' T' является ссылочным типом, а 'T?', Если 'T' - тип значения. Поскольку generics в .NET имеют одну реализацию (в отличие от шаблонов на C++), это нелегко сделать. Теоретически, компилятор мог наклониться назад, чтобы сделать эту работу умной генерации кода. На практике философия компилятора C# заключается не в том, чтобы перегибаться назад, а в том, чтобы запрещать вещи, если они не могут быть сделаны прямо. –