从C/C++到C# (7)

    本篇主要着眼于C#中运算符的重载,以及implicit conversion和explicit conversion运算符的实现,为尽可能直观地编写程序提供方便。

  • C#中,你不能通过重载改变运算符的运算顺序和优先级;不能改变运算符的操作数个数;不能自定义新的运算符;不能改变运算符对内建类型的处理方法;不能重载dot运算符;应该使用indexer来模拟[]运算符,使用property来模拟=运算符,使用delegate来模拟函数调用。
  • 使用operator关键字来进行运算符重载,重载的时候要定义运算符的返回值和参数;所有的运算符都必须是public static的,不能使用virtual/abstract/override/sealed修饰;二元运算符有两个明确的参数,一元运算符有一个明确的参数。

struct Hour

{

    public Hour(int initialValue)

    {

        this.value = initialValue;

    }

    public static Hour operator+ (Hour lhs, Hour rhs)

    {

        return new Hour(lhs.value + rhs.value);

    }

    ...

    private int value;

}

  • 当你使用重载的运算符时,编译器自动将其转换为对用户定义的运算符的调用。

Hour Example(Hour a, Hour b)

{

    return a + b;

}

变为:

Hour Example(Hour a, Hour b)

{

    return Hour.operator+(a,b); // pseudocode

}

  • 在定义运算符的时候,必须至少有一个参数是the containing type(包含你想调用的运算符的类)。例如上面的例子中,至少有一个参数必须是Hour类。
  • 你可以多次重载一个运算符,来处理不同的运算方式。

struct Hour

{

    public Hour(int initialValue)

    {

        this.value = initialValue;

    }

    ...

    public static Hour operator+ (Hour lhs, Hour rhs)

    {

        return new Hour(lhs.value + rhs.value);

}

//下面两个运算符的重载方式是对称的,用于使用户可以自由选择左右操作数的顺序

//C++中你只需要提供一个,编译器会自动Swap

    public static Hour operator+ (Hour lhs, int rhs)

    {

        return lhs + new Hour(rhs);

    }

    public static Hour operator+ (int lhs, Hour rhs)

    {

         return new Hour(lhs) + rhs;

    }

    ...

    private int value;

}

  • 如果你实现了+运算符,最好也实现一个使用同样参数的Add方法,以便符合Common Language Specification (CLS)的要求。
  • C#不允许你声明一个用户定义的=运算符,但是+=等组合运算符会自动转换成+等二元运算符进行操作。
  • C#允许你声明自己的++运算符,并且可以用于前缀和后缀形式,这两个运算符的返回值必须和参数类型一致。

struct Hour

{

    ...

    public static Hour operator++ (Hour arg)

    {

        arg.value++;

        return arg;

    }

    ...

    private int value;

}

  • 如果你在class中定义了重载++/--运算符,要注意因为赋值语句实际上是增加了一个对现有object的引用,所以对其中任何一个的修改都会影响到另外一个,所以上述struct++的实现方式会出现错误如下,下面是postfix=now++的内部过程描述:

Hour now = new Hour(9);

Hour postfix = now;

//下面一句对now的更新也会影响到postfix,出现了错误

now = Hour.operator++(now); // pseudocode, not valid C#

  • 正确的class中的实现如下,但是这会带来内存使用和回收的很大负担,建议尽量不要在class中重载运算符:

class Hour

{

    public Hour(int initialValue)

    {

        this.value = initialValue;

    }

    ...

    public static Hour operator++(Hour arg)

    {

        return new Hour(arg.value + 1);

    }

    ...

    private int value;

}

  • 某些运算符的功能是对称的(例如><<=>=),这时如果你定义了其中的一个,C#编译器会强制你定义另外一个。
  • 如果你定义了==!=运算符,你最好重载从System.Object继承的EqualsGetHashCode方法。
  • 内建的数据类型包含某些隐含的转换(implicit conversion),这些转换永远不会生成exceptionclass Example,隐含转换又被称为widening conversion,因为结果类型的取值范围总是比源类型大(例如int转换成double)。

public static void MyDoubleMethod(double parameter)

{

    ...

}

Example.MyDoubleMethod(42); // implicit int to double conversion

  • 但是,double不能隐含转换为int,必须明确调用castExplicit conversion又被称为narrowing conversion,可以生成OverflowException.

class Example

{

    public static void MyIntMethod(int parameter)

    {

        ...

    }

}

...

Example.MyIntMethod(42.0); // compile-time error

Example.MyIntMethod((int)42.0);

  • 你可以定义自己的转换运算符,语法和重载运算符类似,也必须是public static的;要被转换的类型定义为参数,要转换成的类型定义为运算符名,没有返回值;你必须说明这个转换运算符是implicit还是explicit的。

struct Hour

{

    ...

    public static implicit operator int (Hour from)

    {

        return this.value;

    }

    private int value;

}

class Example

{

    public static void Method(int parameter) { ... }

    public static void Main()

    {

        Hour lunch = new Hour(12);

        Example.MyOtherMethod(lunch); // implicit Hour to int conversion

         //如果转换运算符是explicit的,就必须是Example.MyOtherMethod((int)lunch);

    }

}

  • 转换运算符可以作为解决对称运算符问题的一种方法,例如前面例子中Hour类的三个版本的+运算符(Hour + Hour, Hour + int, and int + Hour)可以使用一个运算符(Hour+Hour)配合一个隐含的int to Hour转换来完成:

struct Hour

{

    public Hour(int initialValue)

    {

        this.value = initialValue;

    }

    public static Hour operator+(Hour lhs, Hour rhs)

    {

        return new Hour(lhs.value + rhs.value);

    }

    public static implicit operator Hour (int from)

    {

        return new Hour (from);

    }

    ...

    private int value;

}

void Example(Hour a, int b)

{

Hour eg1 = a + b; // b converted to an Hour    

Hour eg2 = b + a; // b converted to an Hour

}

(待续,下一篇将主要描述C#Enumable Object的实现和作用)  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值