por que não posso ser compacto com meu polimorfismo desejado C #?
-
06-07-2019 - |
Pergunta
Aqui está o que eu quero fazer:
XmlWriter writer = XmlWriter.Create(
(string.IsNullOrEmpty(outfile) ? Console.Out : outfile)
);
Esta não compila, no entanto, dar o erro "Tipo de expressão condicional não pode ser determinado porque não há nenhuma conversão implícita entre 'System.IO.TextWriter' e 'string'". O código acima é uma simplificação dos procedimentos a seguir:
XmlWriter writer;
if (string.IsNullOrEmpty(outfile))
{
writer = XmlWriter.Create(Console.Out); // Constructor takes TextWriter
}
else
{
writer = XmlWriter.Create(outfile); // Constructor takes string
}
Estas duas chamadas para Create
são perfeitamente válidos, e Isso compila. Existe uma maneira de fazer isso mais compacta, como eu estava tentando fazer com o meu teste em linha?
Não faz sentido para mim que o que eu quero não funciona. Mentalmente pensamento através deste, parece que o compilador avalia string.IsNullOrEmpty(outfile)
para determinar qual caso a tomar:
- Se a condição fosse verdade, iria com
Console.Out
, e depois ver o que ele precisa para escolher polymorphically a versão doXmlWriter.Create
que leva um TextWriter. - Se a condição eram falsos, ele iria com
outfile
, e depois ver o que ele precisa para escolher polymorphically a versão doXmlWriter.Create
que leva uma string.
Tem programação em ML deformado meu cérebro?
Solução
A razão que você não pode fazer isso é porque o compilador deve escolher qual a sobrecarga de Criar para usar em tempo de compilação - a sua abordagem exigiria que seja feito em tempo de execução. O mais curto que você pode fazer é provavelmente:
XmlWriter writer = String.IsNullOrEmpty(outfile)
? XmlWriter.Create(Console.Out)
: XmlWriter.Create(outfile);
Outras dicas
Todo mundo parece estar sugerindo o seguinte:
XmlWriter writer = String.IsNullOrEmpty(outfile)
? XmlWriter.Create(Console.Out)
: XmlWriter.Create(outfile);
No entanto, isso também é factível:
XmlWriter writer = XmlWriter.Create(string.IsNullOrEmpty(outfile)
? Console.Out : new StreamWriter(outfile));
O último é mais perto de sua tentativa original e, IMO, mais compacto.
O compilador C # escolhe um método para executar estaticamente durante a compilação. A IL que é gerado quando você compilar é uma referência a um método específico. A parte polimorfismo vem em tempo de execução quando se escolhe o que a implementação dessa função específica para executar.
Seu:?. Declaração é avaliada em tempo de execução e, como tal, o compilador não consegue descobrir qual método para executar
Mude para isso e ele vai trabalhar.
XmlWriter writer = string.IsNullOrEmpty(outfile) ?
XmlWriter.Create(Console.Out) :
XmlWriter.Create(outfile);
O problema é que você não pode determinar em tempo de compilação que
(string.IsNullOrEmpty(outfile) ? Console.Out : outfile)
deve retornar. Será que vai ser uma string ou é ele que vai ser um TextWriter? Isso só pode ser determinada em tempo de execução, portanto, o erro de compilação porque o? operador tem de ser resolvido em tempo de compilação.
O melhor que você pode sair dela provavelmente seria:
XmlWriter writer = string.IsNullOrEmpty(outfile)
? XmlWriter.Create(Console.Out)
: XmlWriter.Create(outfile);
Um par de coisas estão acontecendo aqui.
Primeiro, a "exceção" está ocorrendo por causa do ternário Operator (tm), não por causa de onde você estiver usando. O problema é porque você tem uma única expressão que está tentando voltar dois tipos diferentes que não podem ser resolvidos a um único, tipo de base comum (que não seja objeto).
Além disso, as sobrecargas construtor provavelmente tomar dois tipos completamente diferentes que não estão relacionados de forma alguma. O compilador C # é muito, muito inteligente, mas não é bastante que inteligente.
Não, você tem que fazer duas chamadas separadas, como eles são dois construtores diferentes.
Qual a sobrecarga de chamada é determinado em tempo de compilação, então você não pode selecionar um tipo de dados em tempo de execução para chamar diferentes sobrecargas.
Além disso, o operador condicional pode retornar apenas um único tipo de dados, você não pode tê-lo retornar diferentes tipos de dados, dependendo da escolha.
C # é digitado estaticamente toda a magia polimorfismo está acontecendo em tempo de compilação. E o tipo da sua expressão condicional não é conhecido no tempo de compilação.