艾伟_转载:.NET 4.0中数组的新增功能

简介:   1、两数组是否“相等”?  在实际开发中,有时我们需要比对两个数组是否拥有一致的元素,例如,以下两个数组由于拥有相同的元素,因此被认为是相等的:int[] arr1 = new int[]{1,2,3,4};int[] arr2 = new int[]{1,2,3,4};  在.NET早期版本中,要实现上述数组比对功能,必须自己动手编写一个函数,在其内部使用循环语句逐个比较两个数组的对应元素,才知道这两个数组是否相等。

  1、两数组是否“相等”?

  在实际开发中,有时我们需要比对两个数组是否拥有一致的元素,例如,以下两个数组由于拥有相同的元素,因此被认为是相等的:

 
 
int [] arr1 = new int []
{
1 , 2 , 3 , 4
};
int [] arr2 = new int []
{
1 , 2 , 3 , 4
};

  在.NET早期版本中,要实现上述数组比对功能,必须自己动手编写一个函数,在其内部使用循环语句逐个比较两个数组的对应元素,才知道这两个数组是否相等。

  在.NET 4.0中,数组基类Array实现了一个新增的接口IStructuralEquatable,从而使得所有数组都可直接比对其所拥有的元素是否相等。

  IStructuralEquatable接口的定义如下,其中最重要的成员就是它所定义的Equals()方法。

 
 
public interface IStructuralEquatable
{
bool Equals( object other, IEqualityComparer comparer);
int GetHashCode(IEqualityComparer comparer);
}

  上述声明中还涉及另一个接口IEqualityComparer,它的声明如下:

 
 
public interface IEqualityComparer
{
bool Equals( object x, object y);
int GetHashCode( object obj);
}

  实现了IEqualityComparer接口的对象被称为“集合对象相等比较器”。

  .NET 4.0基类库中提供了好几个直接可用的“集合对象相等比较器”,有两种方式获取这些预定义的“集合对象相等比较器”:

  (1)使用StructuralComparisons类的静态属性StructuralEqualityComparer获取一个StructuralEqualityComparer类型实例的引用。

  延伸阅读:

  “程序集接口最小化”设计原则

  StructuralComparisons和StructuralEqualityComparer这两个类型均属于System.Collections命名空间,位于.NET的核心程序集mscorlib.dll内,前者是public的,而后者是internal的。

  默认情况下,声明为internal的类型只能在本程序集内使用,其它程序集无法“看到”它。

  因此,StructuralComparisons类在定义其静态属性StructuralEqualityComparer时,没有直接向外界暴露StructuralEqualityComparer类型,而是将其转换为公有的IEqualityComparer接口:

 
 
public static class StructuralComparisons
{
public static IEqualityComparer StructuralEqualityComparer { get ; }
// ……
}

  这种设计方法贯彻了.NET组件化开发中的“程序集接口最小化”原则。该原则说:设计一个程序集时应该尽可能地减少声明为public的类型。

  .NET设计者在设计public类型StructuralComparisons时,没有让其静态属性直接将一个StructuralEqualityComparer对象的引用返回给外界,而将其转换为一个外界“知道”的公有接口IEqualityComparer,从而将StructuralEqualityComparer类型的定义完全封装在程序集内部,外界甚至不知道有这么一个类型的存在。

  这种设计方式的好处是:

  我们可以在程序集内部设计任意多个实现了IEqualityComparer接口的类型,由于这些类型对于外界而言是“透明”的,因此,程序集内部的修改对外界程序集使用者可能带来的影响就很小了。

  这种设计方法值得注意。

  (2)使用EqualityComparer静态属性Default获取一个.NET4.0针对泛型类型T所提供的默认“集合对象相等比较器”对象的引用,同样地,它没有将程序集内部的某个具体类型发布出去,而是玩了一点小花样,发布了一个实现了IEqualityComparer接口的公有抽象基类EqualityComparer:

 
 
public abstract class EqualityComparer :
IEqualityComparer, IEqualityComparer
{
public static EqualityComparer Default { get ; }
// ...
}

  可以将.NET基类库设计者的设计思路表述为下图 。

  因此,使用上述两种方式的任意一种,我们可以写出以下代码来直接判断两个整型数组是否拥有完全一致元素:

 
 
bool IsEqual1 = (arr1 as IStructuralEquatable).Equals(
arr2, StructuralComparisons.StructuralEqualityComparer);
bool IsEqual2 = (arr1 as IStructuralEquatable).Equals(
arr2, EqualityComparer.Default)

  当比对两个数组时,如果两个数组的长度不一样,数组基类Array所实现的IStructuralEquatable.Equals()方法将返回false,否则,它逐个比较两个数组的对应元素,找到一个不同的,返回false,如果一直比较完所有元素,都没有发现有不同的,则Equals()方法返回true。

  2、两个数组“谁大谁小”?

  如果两个数组的长度一样,我们还可以定义这两个数组“谁大谁小”:

 
 
int [] arr1 = new int []
{
1 , 2 , 3 , 4
};
int [] arr2 = new int []
{
1 , 2 , 3 , 5
};

  上述两个数组中,由于arr1与arr2前几个元素都相等,但第4个元素arr2大于arr1,所以,我们认为:arr2“大于”arr1

  为了比较两个集合的大小,.NET 4.0引入了一个新的接口IStructuralComparable,并且让数组基类Array也实现了此接口,这意味着在.NET 4.0中,两个数组对象是可以比较“大小”的。

 
 
public interface IStructuralComparable
{
int CompareTo( object other, IComparer comparer);
}

  注意上面的接口声明中用到了一个实现IComparer接口的“集合对象大小比较器”对象。.NET基类库同样提供了几个默认的“集合对象大小比较器”可供直接使用,也有两种方式获取这些默认的“集合对象大小比较器”实例:

  (1)通过我们前面用过的StructuralComparisons类的另一个静态属性StructuralComparer获取,它在内部使用System.Collections.Comparer类的Default静态属性所引用的包容了本地文化信息(CultureInfo)的Comparer对象来完成比较大小的工作,此对象是CLR在装入程序集时创建的。

  (2)通过Comparer.Default属性获取针对特定类型的默认“集合对象大小比较器”对象。

  由此,我们可以写出以下代码来比较两个整型数组谁大谁小:

 
 
int result1 = (arr1 as IStructuralComparable).CompareTo(
arr2, StructuralComparisons.StructuralComparer);
int result2 = (arr1 as IStructuralComparable).CompareTo(
arr2,Comparer.Default)

  如果arr1>arr2,我们得到“1”;arr1,我们得到“-1”;arr1“等于”arr2,我们得到“0”。

  3、小结

  由于.NET 4.0让数组基类Array实现了IStructuralEquatable和IStructuralComparable两个接口,从而使得所有数组都可以直接比较其内容了。

  通常情况下,使用.NET 4.0提供的几个预定义集合对象比较器就足够了,不过,我们也可以通过定义自己的“集合对象相等比较器”(只需定义一个实现IEqualityComparer 接口的类)或“集合对象大小比较器”(只需定义一个实现IComparer接口的类),从而定义自己的数组比较规则。

  对于其元素为自定义引用类型的数组,推荐让此自定义类型实现IComparable接口,并且重写Object.Equals()方法。这么做的目的是让数组中的所有对象都可以相互比较,并且能直接调用数组基类Array所提供的排序、查找、筛选等功能。

  另外,.NET基类库中相关的设计方案也是值得大家学习借鉴的。

  我在本文中详细介绍了.NET基类库如何设计集合对象相等比较器,但没有介绍它是如何设计集合对象大小比较器的,这个进一步深入探索的任务就留给好奇心强的读者,我只想指出一点,.NET 基类库中,集合对象大小比较器与集合对象相等比较器的设计思路是类似的。

目录
相关文章
|
4月前
|
人工智能 开发框架 .NET
.NET技术的强大功能:.NET技术的基础特性、在现代开发中的应用、以及它如何助力未来的软件开发。
.NET技术是软件开发领域的核心支柱,以其强大功能、灵活性及安全性广受认可。本文分三部分解析:基础特性如多语言支持、统一运行时环境;现代应用如企业级与Web开发、移动应用、云服务及游戏开发;以及未来趋势如性能优化、容器化、AI集成等,展望.NET在不断变化的技术环境中持续发展与创新。
131 4
|
1月前
|
消息中间件 监控 数据可视化
基于.NET开源、功能强大且灵活的工作流引擎框架
基于.NET开源、功能强大且灵活的工作流引擎框架
|
1月前
|
XML 开发框架 .NET
.NET 9 中 LINQ 新增功能实操
.NET 9 中 LINQ 新增功能实操
|
1月前
|
网络协议 Unix Linux
精选2款C#/.NET开源且功能强大的网络通信框架
精选2款C#/.NET开源且功能强大的网络通信框架
|
1月前
|
开发框架 JavaScript 前端开发
2024年全面且功能强大的.NET快速开发框架推荐,效率提升利器!
2024年全面且功能强大的.NET快速开发框架推荐,效率提升利器!
|
1月前
|
网络协议 网络安全 Apache
一个整合性、功能丰富的.NET网络通信框架
一个整合性、功能丰富的.NET网络通信框架
|
1月前
|
消息中间件 开发框架 .NET
.NET 8 强大功能 IHostedService 与 BackgroundService 实战
【11月更文挑战第7天】本文介绍了 ASP.NET Core 中的 `IHostedService` 和 `BackgroundService` 接口及其用途。`IHostedService` 定义了 `StartAsync` 和 `StopAsync` 方法,用于在应用启动和停止时执行异步操作,适用于资源初始化和清理等任务。`BackgroundService` 是 `IHostedService` 的抽象实现,简化了后台任务的编写,通过 `ExecuteAsync` 方法实现长时间运行的任务逻辑。文章还提供了创建和注册这两个服务的实战步骤,帮助开发者在实际项目中应用这些功能。
|
2月前
.NET 4.0下实现.NET4.5的Task类相似功能组件
【10月更文挑战第29天】在.NET 4.0 环境下,可以使用 `BackgroundWorker` 类来实现类似于 .NET 4.5 中 `Task` 类的功能。`BackgroundWorker` 允许在后台执行耗时操作,同时不会阻塞用户界面线程,并支持进度报告和取消操作。尽管它有一些局限性,如复杂的事件处理模型和不灵活的任务管理方式,但在某些情况下仍能有效替代 `Task` 类。
|
2月前
|
开发框架 .NET 开发工具
.NET 9 中 LINQ 新增的功能
.NET 9 中 LINQ 新增的功能
|
4月前
|
开发框架 JavaScript 前端开发
提升生产力:8个.NET开源且功能强大的快速开发框架
提升生产力:8个.NET开源且功能强大的快速开发框架