接线员'?'不能应用于'方法组'类型的操作数

时间:2016-01-20 20:31:15

标签: c# .net c#-6.0

这是关于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 个答案:

答案 0 :(得分:15)

此处?.没有什么特别之处,它与?:的效果相同:logger?.Log会产生与logger == null ? null : logger.Log相同的结果,但logger除外1}}仅被评估一次。

问题是logger == null ? null : logger.Log在早期版本的C#中同样无效。 ?:要求一个操作数可以转换为另一个操作数的类型,但nulllogger.Log都不具有类型。你必须把它写成例如logger == null ? null : (Action<string>) logger.Log

不幸的是,引入该演员表示您无法使用简单漂亮的C#6缩短版本,因为同样适用于?.logger?.Log无效,因为logger.Log没有一个类型,所以logger?.Log也没有类型,但如果它是一个没有类型的表达式,并且它不是一个方法组,那么C#就不会让你这么做。

答案 1 :(得分:0)

如果您能够将界面更改为

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

然后您可以使用logger?.Log表示法。

ILogger的实现看起来像

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

答案 2 :(得分:-1)

添加到@hvd语句

我们还可以使用 Null条件运算符(?。) Null-Coalescing运算符(??)  如果您编写以下代码

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

然后

userName.Length

将抛出异常:“ConsoleApplication中发生了'System.NullReferenceException'类型的未处理异常...  附加信息:对象引用未设置为对象的实例。“

如果您使用以下代码

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

你仍会得到同样的例外

但是

int? len = userName?.Length;

它将返回null并且不会抛出异常

但我们仍有问题。问题是我使用int? (Nullable int)这是不好的,因为人们会更喜欢如果string为null,那么它应该返回0。

所以我们可以通过组合null条件运算符(?。)和空合并运算符(??)

来实现这一点
int len = userName?.Length ?? 0;

<强>加

我们还有另一种使用null条件运算符的方法。

就像在这种情况下处理事件处理时一样,我们可以使用

myCustomEventHandler?.Invoke(this,EventArgs.Empty);

其中“myCustomEventHandler”是C#6.0之前的公共事件,我们必须创建“myCustomEventHandler”的本地副本,否则它可能会在多线程应用程序中抛出异常。而在C#6中,我们可以直接调用“myCustomEventHandler”而不创建本地副本,它是线程安全的。

e.g。在C#5

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

在C#6中

myCustomEventHandler?.Invoke(e)