我刚刚输入了以下代码:
Expression<Func<ContentItem, bool>> expression =
fileTypeGroupID.HasValue ? n => n.Document.MimeType.FileTypeGroupID == fileTypeGroupID.Value : n => true;
Visual Studio 表示无法推断
n
的类型。
代码对我来说似乎很好 - 它只是使用三元运算符将两个
Expression
文字之一分配给 Expression
变量。
Visual Studio 是否不够智能,无法推断三元运算符内
n
的类型,还是我犯了某种错误?
这个问题几乎每天都会以某种形式被问到。
条件运算符类型分析是从inside到outside,而不是从outside到inside。条件运算符不知道其结果被分配给什么类型,然后强制结果和这些类型的替代品。它的作用恰恰相反;它计算出结果和替代的类型,采用这两种类型中更通用的类型,然后验证是否可以分配通用类型。
结果和替代不包含有关 lambda 类型的信息,因此无法推断条件的类型。因此无法验证分配是否正确。
考虑为什么这种语言是这样设计的,是很有启发性的。假设你有超载:
void M(Func<string, int> f) {}
void M(Func<double, double> f) {}
还有一个电话
M( b ? n=>n.Foo() : n => n.Bar() );
描述重载决策如何确定在从外到内推断类型的世界中选择 M 的哪个重载。
现在考虑这个:
M( b1 ? (b2 ? n=>n.Foo() : n => n.Bar() ) : (b3 ? n=>n.Blah() : n=>n.Abc()) );
越来越难了不是吗? 现在想象 Foo、Bar、Blah 和 Abc 本身就是采用 func 的方法,并且还具有包含 lambda 的条件运算符的参数。
我们不希望让类型推断过程变得如此复杂而没有相应的巨大好处,而条件运算符也没有如此巨大的好处。
在您的情况下,您应该做的是将结果和替代方案中的一个或两个转换为特定类型。
Expression<Func<ContentItem, bool>> expression =
fileTypeGroupID.HasValue
? (Expression<Func<ContentItem, bool>>)(n =>
n.Document.MimeType.FileTypeGroupID == fileTypeGroupID.Value;
)
: n => true;
这并不能回答您为什么编译器无法推断类型的问题,但一个简单的解决方法是以这种方式编写表达式:
Expression<Func<ContentItem, bool>> expression =
n => !fileTypeGroupID.HasValue || n.Document.MimeType.FileTypeGroupID == fileTypeGroupID.Value;
fileTypeGroupID.HasValue ? (ContentItem n) => n.Document.MimeType.FileTypeGroupID == fileTypeGroupID.Value
: (ContentItem n) => true;
注意 条件运算符 是
? :
的正确名称,它是三元运算符的示例(并且是许多编程语言中唯一的三元运算符)。