千家信息网

在NullObject中C#6.0有哪些改进

发表于:2025-11-07 作者:千家信息网编辑
千家信息网最后更新 2025年11月07日,今天就跟大家聊聊有关在NullObject中C#6.0有哪些改进,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。什么是空引用异常作为一个敲过代码
千家信息网最后更新 2025年11月07日在NullObject中C#6.0有哪些改进

今天就跟大家聊聊有关在NullObject中C#6.0有哪些改进,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

什么是空引用异常

作为一个敲过代码的码农来说,似乎没有谁没有遇到过NullReferenceException这 个问题,有些时候当方法内部调用一个属性、方法(委托)时,我们控制这些属性在"外部"的表现(当然某些情况下使用ref关键字除外),所以我们要在方法 的内部去判断属性、委托方法是否为Null来避免可能的、错误使用上带来的空引用异常,这样当我们知道如果对象为Null的话,我们会实现符合我们"预 期"的行为。

解决空引用异常---Check Any Where

这很简单,我只要在需要用的地方检查一下是否为Null就可以了。是的,这非常简单,语义也很清晰,但是当你要重复检查一个对象实体10000万次时,你的代码中将存在10000个如下代码段:

public void Check()         {             if (Person.AlivePerson() != null)             {                 Person.AlivePerson().KeepAlive = true;             }          }

你能容忍这样的行为吗?

If(OK)

Continue;

Else

Close;

应用NullObject设计模式

NullObjectPattern出自forth by Gamma(设计模式4人组),核心内容是:提供一个给定对象的空值代理,空值代理中提供不做任何事情的方法实现。

接下来让我们看看维基百科上的C#实现:

// compile as Console Application, requires C# 3.0 or higher using System; using System.Linq; namespace MyExtensionWithExample {     public static class StringExtensions {          public static int SafeGetLength(this string valueOrNull) {              return (valueOrNull ?? string.Empty).Length;          }     }     public static class Program {         // define some strings         static readonly string[] strings = new [] { "Mr X.", "Katrien Duck", null, "Q" };         // write the total length of all the strings in the array         public static void Main(string[] args) {             var query = from text in strings select text.SafeGetLength(); // no need to do any checks here             Console.WriteLine(query.Sum());         // The output will be: 18          }     } }

在C#语言中,我们通过静态的扩展方法来实现将检查方式统一在方法内部,而不是写的到处都是,上面的例子中是在String类上实现了一个SafeGetLength扩展方法,将为所有String类型提供了一个方法,这样我们在"代码整洁"上又进了一步。

下面我们再来看一个更常用的例子---来自于StackOverFlow

public static class EventExtensions     {         public static void Raise(this EventHandler evnt, object sender, T args)             where T : EventArgs         {             if (evnt != null)             {                 evnt(sender, args);             }         }     }

***,说一个细节问题,以上代码均没有实现"线程安全",在大牛Eric Lippert的文章中针对线程安全有过一个更精彩的讨论,请戳这里。

改进后的代码时在方法内部增加了一个临时变量,作为方法内部的拷贝,实现线程安全,如果有疑问请参考我的《C#堆vs栈》中对方法内部变量在堆栈上的表现一章。

public class SomeClass     {         public event EventHandler MyEvent;          private void DoSomething()         {             var tmp = MyEvent;              tmp.Raise(this, EventArgs.Empty);         }     }

更"潮"的方式-C#6.0语法

来自MSDN Magazine的Mark Michaelis(《C#本质论》作者)给我们介绍了C#6.0在语言可能带来的新改进,其中就有针对"Null条件运算符"的改进。

C#6.0更多参考:

Part One: https://msdn.microsoft.com/zh-cn/magazine/dn683793.aspx

Part Two: https://msdn.microsoft.com/zh-cn/magazine/dn802602.aspx

即使是 .NET 开发新手,也可能非常熟悉 NullReferenceException。有一个例外是几乎总是会指出一个 Bug,因为开发人员在调用 (null) 对象的成员之前未进行充分的 null 检查。请看看以下示例:

public static string Truncate(string value, int length) {   string result = value;   if (value != null) // Skip empty string check for elucidation   {     result = value.Substring(0, Math.Min(value.Length, length));   }   return result; }

如果不进行 null 检查,此方法会引发 NullReferenceException。尽管这很简单,但检查字符串参数是否为 null 的过程却稍微有些繁琐。通常,考虑到比较的频率,该繁琐的方法可能没有必要。C# 6.0 包括一个新的 null 条件运算符,可帮助您更加简便地编写这些检查:

public static string Truncate(string value, int length) {             return value?.Substring(0, Math.Min(value.Length, length)); }  [TestMethod] public void Truncate_WithNull_ReturnsNull() {   Assert.AreEqual(null, Truncate(null, 42)); }

根据 Truncate_WithNull_ReturnsNull 方法所演示的内容,如果对象的值实际上为 null,则 null 条件运算符将返回 null。这带来了一个问题,即 null 条件运算符在调用链中出现时会是什么情况?如以下示例中所示:

public static string AdjustWidth(string value, int length) {   return value?.Substring(0, Math.Min(value.Length, length)).PadRight(length); }  [TestMethod] public void AdjustWidth_GivenInigoMontoya42_ReturnsInigoMontoyaExtended() {   Assert.AreEqual(42, AdjustWidth("Inigo Montoya", 42).Length); }

尽管 Substring 是通过 null 条件运算符进行调用的,并且 null value?.Substring 似乎返回了 null,但语言行为按您的想法进行。这简化了对 PadRight 的调用过程,并立即返回 null,从而避免会导致出现 NullReferenceException 的编程错误。这个概念称为"null 传播"。

Null 条件运算符会根据具体条件进行 null 检查,然后再调用目标方法以及调用链中的所有其他方法。这将可能产生一个令人惊讶的结果,例如,text?.Length.GetType 语句中的结果。

如果 null 条件运算符在调用目标为 null 时返回 null,那么调用会返回值类型的成员时最终会是什么数据类型(假定值类型不能为 null)?例如,从 value?.Length 返回的数据类型不能只是 int。答案当然是:可以为 null 的类型(int?)。实际上,尝试仅将结果分配给 int 将会出现编译错误:

int length = text?.Length; // Compile Error: Cannot implicitly convert type 'int?' to 'int'

Null 条件具有两种语法形式。首先,问号在点运算符前面 (?.)。其次,将问号和索引运算符结合使用。例如,给定一个集合(而非在索引到集合之前显式进行 null 检查),您就可以使用 null 条件运算符执行此操作:

public static IEnumerable GetValueTypeItems(   IList collection, params int[] indexes)   where T : struct {   foreach (int index in indexes)   {     T? item = collection?[index];     if (item != null) yield return (T)item;   } }

此示例使用了运算符 ?[…] 的 null 条件索引形式,导致仅在集合不为 null 时才索引到集合。通过 null 条件运算符的此形式,T? item = collection?[index] 语句在行为上相当于:

T? item = (collection != null) ? collection[index] : null.

请注意,null 条件运算符仅可检索项目,不会分配项目。如果给定 null 集合,那么这意味着什么?

请注意针对引用类型使用 ?[…] 时的隐式歧义。由于引用类型可以为 null,因此对于集合是否为 null,或者是否元素本身实际上就是 null 而言,来自 ?[…] 运算符的 null 结果不明确。

Null 条件运算符的一个非常有用的应用程序解决了 C# 自 C# 1.0 以来一直存在的的一个特性,即在调用委托之前检查是否为 null。我们来看一下中显示的 C# 2.0 代码。

图 1 在调用委托之前检查是否为 Null

class Theremostat {   event EventHandler OnTemperatureChanged;   private int _Temperature;   public int Temperature   {     get     {       return _Temperature;     }     set     {       // If there are any subscribers, then       // notify them of changes in temperature       EventHandler localOnChanged =         OnTemperatureChanged;       if (localOnChanged != null)       {         _Temperature = value;         // Call subscribers         localOnChanged(this, value);       }     }   } }

通过使用 null 条件运算符,整个 set 实现过程就可简化为:

OnTemperatureChanged?.Invoke(this, value)

现在,您只需对将 null 条件运算符作为前缀的 Invoke 进行调用,不再需要将委托实例分配给本地变量,从而实现线程安全,甚至是在调用委托之前显式检查值是否为 null。

C# 开发人员都很想知道在***的四个版本中是否对此内容有所改进。答案是最终进行了改进。仅此一项功能就可以改变调用委托的方式。

另一个 null 条件运算符普及的常见模式是与 coalesce 运算符结合使用。您无需在调用 Length 之前对 linesOfCode 进行 null 检查,而是可以编写项目计数算法,如下所示:

List linesOfCode = ParseSourceCodeFile("Program.cs"); return linesOfCode?.Count ?? 0;

在这种情况下,任何空集合(无项目)和 null 集合均标准化为返回相同数量。总之,null 条件运算符将实现以下功能:

1. 如果操作数为 null,则返回 null

2. 如果操作数为 null,则简化调用链中的其他调用

3. 如果目标成员返回一个值类型,则返回可以为 null 的类型 (System.Nullable)。

4. 以线程安全的方式支持委托调用

5. 可用作成员运算符 (?.) 和索引运算符 (?[…])

看完上述内容,你们对在NullObject中C#6.0有哪些改进有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注行业资讯频道,感谢大家的支持。

运算符 运算 条件 方法 检查 类型 C# 委托 代码 内容 安全 对象 索引 线程 方式 结果 行为 项目 变量 实际 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 福建中职网络安全技能竞赛 数据库钟 什么时候需要去数据库校验数据 网络安全知识竞赛答题入口黑龙江 剪辑软件开发哪个比较好 葫芦岛节能软件开发业务 服务器被踢出去是什么意思 饥荒服务器怎么租 张家界软件开发工程师 豆神教育网络安全业务是什么 阿里云数据中心部署的服务器数量 国产自主服务器测评 服务器端口映射软件 UI设计和软件开发人员 移动服务器ping包地址 湖南运营网络技术服务怎么样 大连水利建筑设计院网络安全 服务器之间通过什么连接的 战机网络安全涉及的技术 剑网3 服务器列表 詊算机网络技术 弹弹奇兵华为怎么找之前的服务器 全国网络安全信息峰会 我的世界沉羊的服务器编号 数据库怎么看是否可为空 软件开发运营工作内容 杭州安卡网络技术有限公司好吗 前海微智盛网络技术百度 中国地图版网络技术应用 平台数据库服务器中关村
0