Оператор?"не может быть применен к операнду типа "группа методов"

это вопрос о недавно введенном операторе нулевой проверки C#.

предполагая, что у меня есть интерфейс, такой как:

interface ILogger
{
    void Log(string message);
}

и функция, которая ожидает действия ведения журнала:

void DoWork(Action<string> logAction)
{
    // Do work and use @logAction
}

почему я получаю следующую ошибку компилятора, если я пытаюсь написать:

void Main(string[] args)
{
    ILogger logger = GetLogger(); // Assume GetLogger() may return null

    //
    // Compiler error: 
    // Operator '?' cannot be applied to operand of type 'method group'
    //
    DoWork(logger?.Log);   
}

3 ответов


ничего особенного не происходит с ?. здесь он работает так же, как и с ?:: logger?.Log даст тот же результат, что и logger == null ? null : logger.Log, за исключением logger оценивается только один раз.

проблема в том, что logger == null ? null : logger.Log также недействителен в более ранних версиях C#. ?: требует, чтобы один операнд был конвертируемым в тип другого, но ни null, ни logger.Log тип. Вы должны написать это, например,logger == null ? null : (Action<string>) logger.Log.

к сожалению, введение этого приведения означает, что нет простой довольно сокращенной версии C# 6, которую вы можете использовать, так как то же самое относится к ?.: logger?.Log является недействительным, поскольку logger.Log не имеет типа, так что logger?.Log также не имеет типа, но если это выражение Без типа, и это не группа методов, то C# ничего не позволит вам сделать с ним.


Если вы можете изменить свой интерфейс на

interface ILogger
{
    //void Log(string message);
    Action<string> Log {get; }
}

тогда вы можете использовать logger?.Log нотации.

реализация ILogger будет выглядеть примерно так:

class Logger : ILogger
{
    Action<string> Log => str => { /* Do stuff with str */ };
}

добавление к заявлению @hvd

мы также можем использовать Нулевой Условный Оператор ( ?. ) С Нуль-Коалесцирующий Оператор ( ?? ) Если вы пишете следующий код

string userName = null;
int len = userName.Length;

затем

userName.Length

выдаст исключение: "необработанное исключение типа" System.NullReferenceException ' произошло в ConsoleApplication... Дополнительные сведения: ссылка на объект не указывает на экземпляр объекта."

если вы используете следующий код

string userName = null;
int? len = userName.Length;

все равно вы получите то же исключение

но

int? len = userName?.Length;

он вернет null и не будет выбрасывать исключение

но у нас все еще есть проблема. Проблема в том, что я использую int? (Nullable int), что нехорошо, потому что люди предпочтут, чтобы если строка равна null, то она должна возвращать 0.

таким образом, мы можем сделать это с помощью комбинации нулевого условного оператора(?.) и null-coalescing Оператор (??)

int len = userName?.Length ?? 0;

добавил

у нас есть еще одно использование нулевого условного оператора.

как при работе с обработкой событий в этом случае мы можем использовать

myCustomEventHandler?.Вызов(это, EventArgs в.Пусто);

где "myCustomEventHandler" является публичным событием перед C#6.0 мы должны создать локальную копию "myCustomEventHandler", иначе он может вызвать исключение в случае muti-threaded приложение. в то время как в C# 6 мы можем напрямую вызвать "myCustomEventHandler" без создания локальной копии, и это потокобезопасно.

например, в C# 5

var handler= this.myCustomEventHandler;
if (handler!= null)
    handler(…)

в C# 6

myCustomEventHandler?.Invoke(e)