C# 运算符'';无法应用于类型为';T';(2)
我遇到了C#编译器(VS 2015)的一个奇怪行为。 在下面的代码中,编译器对Value2感到满意,但对Value1表示不满:运算符“?”不能应用于类型为“T”的操作数 为什么?C# 运算符'';无法应用于类型为';T';(2),c#,C#,我遇到了C#编译器(VS 2015)的一个奇怪行为。 在下面的代码中,编译器对Value2感到满意,但对Value1表示不满:运算符“?”不能应用于类型为“T”的操作数 为什么? 公共接口提供程序 { T值{get;} } 类验证器 { 公共验证器(IValueProvider提供程序) { _valueProvider=提供者; } 公共T值1=>_valueProvider?.Value??默认值(T); public T Value2=>\u valueProvider!=null?\u
公共接口提供程序
{
T值{get;}
}
类验证器
{
公共验证器(IValueProvider提供程序)
{
_valueProvider=提供者;
}
公共T值1=>_valueProvider?.Value??默认值(T);
public T Value2=>\u valueProvider!=null?\u valueProvider.Value:默认值(T);
私有只读IValueProvider _valueProvider;
}
我认为问题在于编译器无法知道表达式的类型\u valueProvider?.Value
让我们简化一下:
public interface IValueProvider<T>
{
T Value { get; }
}
public class Test
{
public static void Foo<T>(IValueProvider<T> provider)
{
var mystery = provider?.Value;
}
}
如果将T
约束为不可为空的值类型,则可以,并且表达式的类型为T?
(也称为nullable
)
publicstaticvoidfoo(IValueProvider提供程序),其中T:struct
{
//变量的类型为Nullable
var神秘=提供者?.Value;
}
但是如果没有这两个约束,就没有有效的翻译。此代码:
public interface IValueProvider<T>
{
T Value { get; }
}
public class Validator<T>
{
public Validator(IValueProvider<T> provider)
{
var providerValue = provider?.Value;
}
}
i、 e
这是不允许的,因为int
不可为空
其余的错误都是从那里慢慢产生的。因此,将
T
约束为可空类型,例如where T:class
,它将工作。这并不奇怪<代码>?对于不可为空的类型(即结构)没有意义。如果没有类型约束,编译器不知道t是否为结构Value2
在任何地方都不使用此运算符,这就是它工作的原因。@PanagiotisKanavos:但是\U valueProvider
不是t
类型,它是IValueProvider
@CodeMaster类型。相反,它非常清楚,代码片段再现了问题。只需在LinqPad中尝试此操作,您就会立即发现问题。@CodeCaster此代码足以让其他人重现并理解错误。答案应该清楚地表明编译器错误与值有关,因为每个人都假设错误与值有关provider@CodeCaster:说实话,比实际需要多一点,但不是很多。这是一个绝对最小的例子吗?否。它是否足够接近以避免大量完全不相关的代码?绝对地它是完整的,允许问题真的很容易再现吗?是的。更简单地说,错误指的是.Value
,而不是提供者
。您在哪里看到“无法解除…”消息?@Henk VS2017 with ReSharper。
public static void Foo<T>(IValueProvider<T> provider) where T : class
{
// Variable is of type T
var mystery = provider?.Value;
}
public static void Foo<T>(IValueProvider<T> provider) where T : struct
{
// Variable is of type Nullable<T>
var mystery = provider?.Value;
}
public interface IValueProvider<T>
{
T Value { get; }
}
public class Validator<T>
{
public Validator(IValueProvider<T> provider)
{
var providerValue = provider?.Value;
}
}
var providerValue = provider?.Value;
int providerValue = null;