操作员 '?'不能应用于 'method group' 类型的操作数
Operator '?' cannot be applied to operand of type 'method group'
这是一个关于 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);
}
这里 ?.
没有什么特别之处,它的工作方式与 ?:
相同: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# 将无能为力。
添加到@hvd 语句
我们还可以使用 空条件运算符 ( ?. ) 和 Null-Coalescing 运算符 ( ?? )
如果你写下面的代码
string userName = null;
int len = userName.Length;
然后
userName.Length
将抛出异常:“'System.NullReferenceException' 类型的未处理异常发生在 ConsoleApplication 中...
附加信息:未将对象引用设置为对象的实例。"
如果你使用下面的代码
string userName = null;
int? len = userName.Length;
你仍然会得到同样的异常
但是
int? len = userName?.Length;
它将return null 并且不会抛出异常
但我们仍有问题。问题是我正在使用 int? (Nullable int) 这不好,因为人们更喜欢如果字符串为 null 那么它应该 return 0.
所以我们可以通过空条件运算符(?.)和null-coalescing运算符(??)
的组合来做到这一点
int len = userName?.Length ?? 0;
已添加
我们还有空条件运算符的另一种用法。
比如当你处理事件时,我们可以使用
myCustomEventHandler?.Invoke(this, EventArgs.Empty);
其中 "myCustomEventHandler" 是 C#6.0 之前的 public 事件,我们必须创建 "myCustomEventHandler" 的本地副本,否则它可能会在 muti-threaded 应用程序的情况下抛出异常。而在 C# 6 中,我们可以直接调用 "myCustomEventHandler" 而无需创建本地副本,并且它是线程安全的。
例如在 C# 5
var handler= this.myCustomEventHandler;
if (handler!= null)
handler(…)
在 C# 6 中
myCustomEventHandler?.Invoke(e)
如果您可以将界面更改为
interface ILogger
{
//void Log(string message);
Action<string> Log {get; }
}
那么你可以使用 logger?.Log
表示法。
ILogger 实现看起来像
class Logger : ILogger
{
Action<string> Log => str => { /* Do stuff with str */ };
}
这是一个关于 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);
}
这里 ?.
没有什么特别之处,它的工作方式与 ?:
相同: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# 将无能为力。
添加到@hvd 语句
我们还可以使用 空条件运算符 ( ?. ) 和 Null-Coalescing 运算符 ( ?? ) 如果你写下面的代码
string userName = null;
int len = userName.Length;
然后
userName.Length
将抛出异常:“'System.NullReferenceException' 类型的未处理异常发生在 ConsoleApplication 中... 附加信息:未将对象引用设置为对象的实例。"
如果你使用下面的代码
string userName = null;
int? len = userName.Length;
你仍然会得到同样的异常
但是
int? len = userName?.Length;
它将return null 并且不会抛出异常
但我们仍有问题。问题是我正在使用 int? (Nullable int) 这不好,因为人们更喜欢如果字符串为 null 那么它应该 return 0.
所以我们可以通过空条件运算符(?.)和null-coalescing运算符(??)
的组合来做到这一点int len = userName?.Length ?? 0;
已添加
我们还有空条件运算符的另一种用法。
比如当你处理事件时,我们可以使用
myCustomEventHandler?.Invoke(this, EventArgs.Empty);
其中 "myCustomEventHandler" 是 C#6.0 之前的 public 事件,我们必须创建 "myCustomEventHandler" 的本地副本,否则它可能会在 muti-threaded 应用程序的情况下抛出异常。而在 C# 6 中,我们可以直接调用 "myCustomEventHandler" 而无需创建本地副本,并且它是线程安全的。
例如在 C# 5
var handler= this.myCustomEventHandler;
if (handler!= null)
handler(…)
在 C# 6 中
myCustomEventHandler?.Invoke(e)
如果您可以将界面更改为
interface ILogger
{
//void Log(string message);
Action<string> Log {get; }
}
那么你可以使用 logger?.Log
表示法。
ILogger 实现看起来像
class Logger : ILogger
{
Action<string> Log => str => { /* Do stuff with str */ };
}