Não é possível usar o operador ternário para atribuir a expressão Linq

Acabei de digitar o seguinte código:

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

O Visual Studio está dizendo que não pode inferir o tipo de n .

O código parece bem para mim – é apenas usando um operador ternário para atribuir um dos dois literais de Expression para uma variável de Expression .

O Visual Studio não é inteligente o suficiente para inferir o tipo de n dentro de um operador ternário, ou cometi algum tipo de erro?

Esta pergunta é feita quase todos os dias de alguma forma.

A análise do tipo de operador condicional procede de dentro para fora , não de fora para dentro . O operador condicional não sabe a que tipo seus resultados estão sendo atribuídos e então coage a consequência e a alternativa a esses tipos . Faz o oposto; ele trabalha os tipos de consequência e alternativa, toma o mais geral desses dois tipos e, em seguida, verifica que o tipo geral pode ser atribuído.

A consequência e a alternativa não contêm nenhuma informação sobre o tipo de lambda e, portanto, o tipo de condicional não pode ser inferido. Portanto, não é possível verificar se a atribuição está correta.

É edificante considerar por que a linguagem foi projetada dessa maneira. Suponha que você tenha sobrecargas:

  void M(Func f) {} void M(Func f) {} 

e uma chamada

 M( b ? n=>n.Foo() : n => n.Bar() ); 

Descrever como a resolução de sobrecarga determina qual sobrecarga de M é escolhida em um mundo onde os tipos são inferidos de fora para dentro.

Agora considere este:

 M( b1 ? (b2 ? n=>n.Foo() : n => n.Bar() ) : (b3 ? n=>n.Blah() : n=>n.Abc()) ); 

Ficando mais difícil, não é? Agora imagine que Foo, Bar, Blah e Abc eram methods que faziam funcs, e também tinham argumentos com operadores condicionais contendo lambdas.

Não desejamos tornar o processo de inferência de tipos tão complexo sem um enorme benefício correspondente, e não há um benefício tão grande para o operador condicional.

O que você deve fazer no seu caso é lançar uma ou ambas as consequências e alternativas para o tipo específico.

Isso não lhe responde a pergunta de por que o compilador não pôde inferir o tipo, mas um trabalho fácil seria escrever sua expressão desta forma:

 Expression> expression = n => !fileTypeGroupID.HasValue || n.Document.MimeType.FileTypeGroupID == fileTypeGroupID.Value; 
 fileTypeGroupID.HasValue ? (ContentItem n) => n.Document.MimeType.FileTypeGroupID == fileTypeGroupID.Value : (ContentItem n) => true; 

Observe o operador condicional é o nome correto para ? : ? : É um exemplo de um operador ternário (e é o único operador ternário em muitas linguagens de programação).