这是关于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);
}
答案 0 :(得分:15)
此处?.
没有什么特别之处,它与?:
的效果相同:logger?.Log
会产生与logger == null ? null : logger.Log
相同的结果,但logger
除外1}}仅被评估一次。
问题是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#就不会让你这么做。
答案 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)