接线员'?'不能应用于类型的操作数' T' (2)

时间:2017-05-25 07:26:13

标签: c#

我遇到了C#编译器的奇怪行为(VS 2015)。 在下面的代码中,编译器对Value2感到满意,但抱怨Value1:Operator'?'不能应用于' T'

类型的操作数

为什么?

public interface IValueProvider<T>
{
    T Value { get; }
}

class Validator<T>
{
    public Validator(IValueProvider<T> provider)
    {
        _valueProvider = provider;
    }

    public T Value1 => _valueProvider?.Value ?? default(T);

    public T Value2 => _valueProvider != null ? _valueProvider.Value : default(T);

    private readonly IValueProvider<T> _valueProvider;
}

2 个答案:

答案 0 :(得分:18)

我认为问题在于编译器无法知道表达式_valueProvider?.Value的类型。

让我们简化一下:

public interface IValueProvider<T>
{
    T Value { get; }
}

public class Test
{
    public static void Foo<T>(IValueProvider<T> provider)
    {
        var mystery = provider?.Value;
    }
}

编译器应该推断出mystery的类型是什么?

  • 如果T是引用类型或可空值类型,则表达式(因此mystery)的类型为T是有意义的。

  • 如果T不可为空的值类型,那么表达式(因此mystery)的类型{{1}是有意义的}}

由于T?没有限制,因此没有合适的类型可供使用,因此存在(稍有不幸)错误消息。

如果属性属于Tstringint,则所有这些都可以,并且表达式的类型为int?,{{1分别和string。但是int?没有相同的内容。

如果您将int?限制为引用类型,那么表达式为T

T

如果您将T限制为不可为空的值类型,那么表达式为public static void Foo<T>(IValueProvider<T> provider) where T : class { // Variable is of type T var mystery = provider?.Value; } (又名T)。

T?

但如果没有任何约束,那么就没有有效的翻译。

答案 1 :(得分:3)

此代码:

public interface IValueProvider<T>
{
    T Value { get; }
}

public class Validator<T>
{
    public Validator(IValueProvider<T> provider)
    {
        var providerValue = provider?.Value;
    }
}

provider?.Value显示此错误:

  

运营商&#39;?&#39;不能应用于类型的操作数&#39; T&#39;

ReSharper给出了这个提示:

  

无法将条件访问表达式T提升为可空类型

由于provider.Value的类型为T,且未受约束,因此您可以为T传递不可为空的类型。

假设您将其与var validator = new Validator<int>(null);一起使用,那么就会发生这种情况:

var providerValue = provider?.Value;

int providerValue = null;

不允许这样做,因为int不可为空。

其余的错误从那里涓涓细流。因此,将T限制为可以为空的类型,例如where T : class,并且它可以正常工作。