C#学习笔记(二十四)-- 值比较

  考虑两个表示人的Person对象,它们都有一个Age整型属性。下面要比较它们,看看哪个人年龄较大。为此可以使用以下代码:

if(person1.Age > person2.Age)
{
   ...
}

  这是可以的,但还有其他方法,例如,使用下面的语法:

if(person1 > person2)
{
   ...
}

  可以使用运算符重载,如本节后面所述。这是一项强大的技术,但应谨慎使用。在上面的代码中,年龄的比较不是非常明显,该段代码还可以比较身高、体重、IQ等。

  另一个方法是使用IComparable和IComparer接口,它们可采用标准方式定义比较对象的过程。.NET Framework中的各种集合类支持这种方式,这使得它们成为对集合中对象进行排序的一种极佳方式。

  1)运算符重载

  通过运算符重载,可以对我们设计的类使用标准的运算符,例如+、>等。这称为重载,因为在使用特定的参数类型时,我们为这些运算符提供了自己的实现代码,其方式与重载方法相同,也是为同名方法提供不同的参数。

  要重载运算符,可给类添加运算符类型成员(它们必须是static)。一些运算符有多种用途(如 - 运算符就有一元和二元两种功能),因此我们还指定了要处理多少个操作数,以及这些操作数的类型。一般情况下,操作数的类型与定义运算符的类相同,但也可以定义处理混合类型的运算符。

  考虑一个简单类型AddClass1,要重载+运算符,可使用下述代码:

public class AddClass1
{
   public int Val;
   public static AddClass1 operator + (AddClass1 op1, AddClass1 op2)
   {
      AddClass1 returnVal = new AddClass1();
      returnVal.val = op1.val + op2.val;
      return returnVal;
   }

}

  可以看出,运算符重载看起来与标准静态方法声明类似,但它们使用关键字operator和运算符本身,而不是一个方法名。现在可以成功地使用+运算符和这个类,如上面的示例所示:

AddClass1 op3 = op1 + op2;

  重载所有的二元运算符都是一样的,一元运算符看起来也是类似的,但只有一个参数:

public class AddClass1
{
   public int val;
   public static AddClass1 operator + (AddClass1 op1, AddClass1 op2)
   {
      AddClass1 returnVal = new AddClass1();
      returnVal.val = op1.val + op2.val;
      return returnVal;
   }
}
public class AddClass2
{
   public int val;
}
public class AddClass3
{
   public int val;
}

  下面的代码就可以执行:

AddClass1 op1 = new AddClass1();
op1.val = 5;
AddClass2 op2 = new AddClass2();
op2.val = 5;
AddClass3 op3 = op1 +op2;

  可以酌情采用这种方式混合类型。但要注意,如果把相同的运算符添加到AddClass2中,上面的代码就会失败,因为它弄不清要是用哪个运算符。因此,应注意不要把签名相同的运算符添加到多个类中。

  还要注意,如果混合了类型,操作数的顺序必须与运算符重载的参数顺序相同。如果使用了重载的运算符和顺序错误的操作数,操作就会失败。所以不能像下面这样使用运算符:

AddClass3 op3 = op2 + op1;

  以下运算符都可以进行重载:

  一元运算符:+,- ,!,~,++,-- ,true,false

  二元运算符:+,- ,* ,/ ,% ,& , | ,^ ,<< ,>>

  比较运算符:==,!=,<,>,<=,>=

  注意:

  如果重载true和false运算符,就可以在布尔表达式中使用类,例如,if(op 1){}。

  不能重载赋值运算符,例如+=,但这些运算符使用与它们对应的简单运算符,例如+,所以不必担心它们。重载+意味着+=如期执行。=运算符不能重载,因为它有一个基本用途。但这个运算符与用户定义的转换运算符相关。

  也不能重载&&和||,但它们使用相应额运算符&和|执行计算,所以重载&和|就足够了。

  一些运算符(如<和>)必须成对重载。这就是说,如果重载>,就必须也重载<。许多情况下,可以在这些运算符中调用其他运算符,以减少需要的代码数量(和可能发生的错误)。

public class AddClass1
{
   public int val;
   public static bool operator >= (AddClass1 op1, AddClass1 op2) => (op1.val >= op2.val);
   public static bool operator < (AddClass1 op1, AddClass1 op2) => !(op1 >= op2);
   //Also need implementaion for <= and > operators.
}

  在较复杂的运算定义中,这可以减少代码行数。这也意味着,如果后来决定修改这些运算符的实现代码,需要改动的代码将较少。

  这同样适用于==和!=,但对于这些运算符,通常需要重写Object.Equals()和Object.GetHashCode(),因为这两个函数也可以用于比较对象。重写这些方法,可以确保无论类的用户使用什么技术,都能得到相同的结果。这不太重要,但应增加进来,以保证其完整性。它需要下述非静态重写方法:

public class AddClass1
{
   public int val;
   public static bool operator == (AddClass1 op1, AddClass1 op2) => (op1.val == op2.val);
   public static bool operator != (AddClass1 op1, AddClass1 op2) => (op1 == op2);
   public override bool Equals(object op1) => val == ((AddClass1)op1).val;
   public override int GetHashCode() => val;
}

  GetHashCode()可根据其状态,获取对象实例的一个唯一int值。这里使用val就可以了,因为它也是一个int值。

  注意,Equals()使用object类型参数。我们需要使用这个签名,否则就将重载这个方法,而不是重写它。类的用户仍可以访问默认的实现代码。这样就必须使用数据类型转换得到所需的结果。这常需要使用本章前面讨论的is运算符检查对象类型,代码如下所示:

public override bool Equals(object op1)
{
   if(op1 is AddClass1)
   {
      return val == ((AddClass1)op1).val;
   }
   else 
   {
      throw new ArgumentException("Cannot compare AddClass1 objects with objects of type" + op1.GetType().ToString());
   }
}

  这段代码中,如果传递给Equals的操作数的类型有误,或者不能转换为正确的类型,就会抛出一个异常。当然,这可能并不是我们希望的操作。我们要比较一个类型的对象和另一个类型的对象,此时需要更多的分支结构。另外,可能只允许对类型完全相同的两个对象进行比较,这需要对第一个if语句做如下修改:

if(op1.GetType() == typeof(AddClass1))
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值