我遇到了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;
}
答案 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?
没有限制,因此没有合适的类型可供使用,因此存在(稍有不幸)错误消息。
如果属性属于T
,string
或int
,则所有这些都可以,并且表达式的类型为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
,并且它可以正常工作。