почему я не могу быть компактным с желаемым полиморфизмом C#?

StackOverflow https://stackoverflow.com/questions/1615351

  •  06-07-2019
  •  | 
  •  

Вопрос

Вот что я хочу сделать:

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

Однако это не компилируется, что приводит к ошибке «Тип условного выражения не может быть определен, поскольку не существует неявного преобразования между «System.IO.TextWriter» и «строка».Приведенный выше код представляет собой упрощение следующего:

XmlWriter writer;

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

Эти два вызова Create совершенно действительны, и это компилируется.Есть ли способ сделать это более компактным, как я пытался сделать в своем встроенном тесте?

Для меня не имеет смысла, что то, что я хочу, не работает.Мысленно обдумывая это, кажется, что компилятор оценит string.IsNullOrEmpty(outfile) чтобы определить, какой случай следует принять:

  • Если бы условие было истинным, оно бы соответствовало Console.Out, а затем увидеть, что ему нужно полиморфно выбрать версию XmlWriter.Create для этого требуется TextWriter.
  • Если бы условие было ложным, оно бы соответствовало outfile, а затем увидеть, что ему нужно полиморфно выбрать версию XmlWriter.Create для этого требуется строка.

Программирование на ML исказило мой мозг?

Это было полезно?

Решение

Причина, по которой вы не можете этого сделать, заключается в том, что компилятор должен выбрать, какую перегрузку Create использовать во время компиляции - ваш подход потребует, чтобы это было сделано во время выполнения.Самое короткое, что вы можете сделать, вероятно, это:

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

Другие советы

Кажется, все предлагают следующее:

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

Однако это также выполнимо:

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

Последний ближе к вашей первоначальной попытке и, по моему мнению, более компактен.

Компилятор C# выбирает метод для статического выполнения во время компиляции.IL, который генерируется при компиляции, является ссылкой на определенный метод.Часть полиморфизма появляется во время выполнения, когда он выбирает, какую реализацию этой конкретной функции выполнить.

Твой ?:Оператор оценивается во время выполнения, и поэтому компилятор не может определить, какой метод выполнить.

Измените это, и это будет работать.

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

Проблема в том, что вы не можете определить во время компиляции, что

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

должен вернуться.Это будет строка или TextWriter?Это можно определить только во время выполнения, отсюда и ошибка компиляции, поскольку ?оператор должен быть разрешен во время компиляции.

Лучшее, что вы можете получить от этого, вероятно, будет:

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

Здесь происходит несколько вещей.

Во-первых, «исключение» возникает из-за Тернарного оператора (tm), а не из-за того, где вы его используете.Проблема в том, что у вас есть одно выражение, которое пытается вернуть два разных типа, которые невозможно преобразовать в один общий базовый тип (отличный от объекта).

Кроме того, ваши перегрузки конструктора, вероятно, принимают два совершенно разных типа, которые никак не связаны между собой.Компилятор C# очень очень умно, но это не совсем что умный.

Нет, вам нужно сделать два отдельных вызова, поскольку это два отдельных конструктора.

Какая перегрузка вызывается, определяется во время компиляции, поэтому вы не можете выбрать тип данных во время выполнения для вызова разных перегрузок.

Кроме того, условный оператор может возвращать только один тип данных, вы не можете заставить его возвращать разные типы данных в зависимости от выбора.

C# статически типизирован, вся магия полиморфизма происходит во время компиляции.И тип вашего условного выражения неизвестен во время компиляции.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top