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 do XmlWriter.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 do XmlWriter.Create que leva uma string.

Tem programação em ML deformado meu cérebro?

Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top