Pregunta

Esto es lo que quiero hacer:

XmlWriter writer = XmlWriter.Create(
    (string.IsNullOrEmpty(outfile) ? Console.Out : outfile)
);

Sin embargo, esto no se compila, lo que da el error " El tipo de expresión condicional no se puede determinar porque no hay una conversión implícita entre 'System.IO.TextWriter' y 'cadena' " ;. El código anterior es una simplificación de lo siguiente:

XmlWriter writer;

if (string.IsNullOrEmpty(outfile))
{
    writer = XmlWriter.Create(Console.Out); // Constructor takes TextWriter
}
else
{
    writer = XmlWriter.Create(outfile); // Constructor takes string
}

Estas dos llamadas a Crear son perfectamente válidas, y esto se compila. ¿Hay alguna manera de hacer que esto sea más compacto, como intenté hacerlo con mi prueba en línea?

No tiene sentido para mí que lo que quiero no funcione. Pensando mentalmente en esto, parece que el compilador evaluará string.IsNullOrEmpty (outfile) para determinar qué caso tomar:

  • Si la condición fuera verdadera, iría con Console.Out , y luego vería que debe elegir polimórficamente la versión de XmlWriter.Create que toma un TextWriter .
  • Si la condición fuera falsa, iría con outfile , y luego vería que debe elegir polimórficamente la versión de XmlWriter.Create que toma una cadena.

¿La programación en ML ha distorsionado mi cerebro?

¿Fue útil?

Solución

La razón por la que no puede hacerlo es porque el compilador debe elegir qué sobrecarga de Crear usar en el momento de la compilación; su enfoque requeriría que se haga en tiempo de ejecución. Lo más corto que puedes hacer es probablemente:

XmlWriter writer = String.IsNullOrEmpty(outfile)
    ? XmlWriter.Create(Console.Out)
    : XmlWriter.Create(outfile);

Otros consejos

Todo el mundo parece sugerir lo siguiente:

XmlWriter writer = String.IsNullOrEmpty(outfile)
    ? XmlWriter.Create(Console.Out)
    : XmlWriter.Create(outfile);

Sin embargo, esto también es factible:

XmlWriter writer = XmlWriter.Create(string.IsNullOrEmpty(outfile)
    ? Console.Out : new StreamWriter(outfile));

Este último está más cerca de su intento original y, IMO, más compacto.

El compilador de C # elige un método para ejecutarse de forma estática durante la compilación. La IL que se genera al compilar es una referencia a un método específico. La parte de polimorfismo entra en tiempo de ejecución cuando elige qué implementación de esa función específica ejecutar.

Tu declaración?: se evalúa en tiempo de ejecución y, como tal, el compilador no puede determinar qué método ejecutar.

Cambia a esto y funcionará.

XmlWriter writer = string.IsNullOrEmpty(outfile) ? 
    XmlWriter.Create(Console.Out) :
    XmlWriter.Create(outfile);

El problema es que no se puede determinar en tiempo de compilación qué

(string.IsNullOrEmpty(outfile) ? Console.Out : outfile)

debería volver. ¿Va a ser una cadena o va a ser un TextWriter? Eso solo se puede determinar en tiempo de ejecución, de ahí el error de compilación porque el? El operador debe resolverse en tiempo de compilación.

Lo mejor que puedes sacar de esto probablemente sería:

XmlWriter writer = string.IsNullOrEmpty(outfile)
    ? XmlWriter.Create(Console.Out)
    : XmlWriter.Create(outfile);

Un par de cosas están sucediendo aquí.

Primero, la " excepción " está ocurriendo debido al Operador Ternario (tm), no debido a dónde lo está utilizando. El problema se debe a que tiene una sola expresión que intenta devolver dos tipos diferentes que no se pueden resolver en un solo tipo de base común (que no sea un objeto).

Además, las sobrecargas de tu constructor probablemente toman dos tipos completamente diferentes que no están relacionados de ninguna manera. El compilador de C # es muy, muy inteligente, pero no es tan tan inteligente.

No, tienes que hacer dos llamadas separadas, ya que son dos constructores separados.

La sobrecarga de la llamada se determina en el momento de la compilación, por lo que no puede seleccionar un tipo de datos en el tiempo de ejecución para llamar a diferentes sobrecargas.

Además, el operador condicional solo puede devolver un solo tipo de datos, no puede hacer que devuelva diferentes tipos de datos según la elección.

C # está tipificado estáticamente, todo el polimorfismo mágico está ocurriendo en tiempo de compilación. Y el tipo de su expresión condicional no se conoce en el momento de la compilación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top