不能使用三元运算符来赋值 Linq 表达式

问题描述 投票:0回答:3

我刚刚输入了以下代码:

Expression<Func<ContentItem, bool>> expression = 
                fileTypeGroupID.HasValue ? n => n.Document.MimeType.FileTypeGroupID == fileTypeGroupID.Value : n => true;

Visual Studio 表示无法推断

n
的类型。

代码对我来说似乎很好 - 它只是使用三元运算符将两个

Expression
文字之一分配给
Expression
变量。

Visual Studio 是否不够智能,无法推断三元运算符内

n
的类型,还是我犯了某种错误?

c# linq type-inference linq-expressions
3个回答
14
投票

这个问题几乎每天都会以某种形式被问到。

条件运算符类型分析是从insideoutside,而不是从outsideinside。条件运算符不知道其结果被分配给什么类型,然后强制结果和这些类型的替代品。它的作用恰恰相反;它计算出结果和替代的类型,采用这两种类型中更通用的类型,然后验证是否可以分配通用类型。

结果和替代不包含有关 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;

2
投票

这并不能回答您为什么编译器无法推断类型的问题,但一个简单的解决方法是以这种方式编写表达式:

Expression<Func<ContentItem, bool>> expression = 
  n => !fileTypeGroupID.HasValue || n.Document.MimeType.FileTypeGroupID == fileTypeGroupID.Value;

1
投票
fileTypeGroupID.HasValue ? (ContentItem n) => n.Document.MimeType.FileTypeGroupID == fileTypeGroupID.Value
                         : (ContentItem n) => true;

注意 条件运算符

? :
的正确名称,它是三元运算符的示例(并且是许多编程语言中唯一的三元运算符)。

© www.soinside.com 2019 - 2024. All rights reserved.