Вы можете сделать это:
ILogger logger = suppressLogging ? (ILogger)(new SuppressLogger()) : (ILogger)(new ConsoleLogger());
Если у вас есть выражение вроде condition ? a : b
, должно быть неявное преобразование из типа a
в тип b
или наоборот, иначе компилятор не может определить тип выражения. В вашем случае нет преобразования между SuppressLogger
и ConsoleLogger
...
(подробнее см. Раздел 7.14 в спецификациях языка C # 4)
Проблема в том, что правая часть оператора вычисляется без учета типа переменной, которой она назначена.
Компилятор не может взглянуть на
suppressLogging ? new SuppressLogger() : new ConsoleLogger();
и решить, каким должен быть возвращаемый тип, поскольку между ними нет неявного преобразования. Он не ищет общих предков, и даже если бы он это сделал, как бы он узнал, кого выбрать.
Каждый раз, когда вы меняете переменную одного типа на переменную другого типа, это преобразование. Присвоение экземпляра класса переменной любого типа, кроме этого, требует преобразования. Это утверждение:
ILogger a = new ConsoleLogger();
выполнит неявное преобразование из ConsoleLogger в ILogger, что является законным, поскольку ConsoleLogger реализует ILogger. Точно так же это будет работать:
ILogger a = new ConsoleLogger();
ILogger b = suppress ? new SuppressLogger() : a;
, потому что существует неявное преобразование между SuppressLogger и ILogger. Однако, это не сработает:
ILogger c = suppress ? new SuppressLogger() : new ConsoleLogger();
, потому что третичный оператор будет очень стараться выяснить, какой тип вам нужен в результате. По сути, он делает это:
В частности, он не начнет поиск по всем типам, которые он знает о поиске типа «наименьшего общего знаменателя», такого как общий интерфейс. Кроме того, вычисляется третичный оператор и определяется его тип возвращаемого значения, независимый от типа переменной, в которой вы сохраняете результат. Это двухэтапный процесс:
Типотипирование одного или обоих ваших операндов является правильным способом выполнения этой операции, если это то, что вам нужно.