C#中如何利用操作符重载和转换操作符

原文:C#中如何利用操作符重载和转换操作符

操作符重载

有的编程语言允许一个类型定义操作符应该如何操作类型的实例,比如string类型和int类型都重载了(==)和(+)等操作符,当编译器发现两个int类型的实例使用+操作符的时候,编译器会生成把两个整数加到一起的代码。

当编译器发现两个string类型的实例使用+操作符的时候,编译器会生成把两个字符串连接到一起的代码。那么编译器怎么就会知道这样做呢?如何进行操作符重载呢?

下面C#代码展示了一个类中如何进行操作符重载:

namespace DoNet.Seven.ConsoleApplicationTest
{
    class Program
    {
        static void Main(string[] args)
        {
            rational r1 = new rational(10);
            rational r2 = new rational(5);
            rational r3= r1 + r2;
            Console.WriteLine(r3.Value);
            Console.ReadKey();

        }
    }
    //有理数
    public sealed class rational
    {
        private int _value = 0;

        public int Value
        {
            get { return _value; }
            set { _value = value; }
        }
        public rational(int value)
        {
            this._value = value;
        }

        public rational()
        {

        }
        public static rational operator+(rational num1,rational num2)
        {
            rational result = new rational(num1.Value+num2.Value);
            return result;
        }

    }
}

运行代码输入结果是15

用IL工具看下编译器生成的代码如下:

1、首先CLR规范要求操作符重载方法必须是public和static方法。另外,C#编译器要求操作符重载方法至少有一个参数的类型与当前定义的这个方法的类型相同。之所以这样做,

是为了是编译器能在合理的时间内找到要绑定的操作符方法。

2、编程语言的编译器看到源码中出现一个+操作符时,会检查是否有一个操作数的类型定义了一个名为op_Addtion的specialname方法,而且该方法的参数兼容于操作数的类型,

如果存在这样的一个方法,编译器就生成调用它的代码。如果不存在这样的一个方法,就生成一个编译错误。

3、对于其它操作符编译之后对应的方法如下表所示(左边是一元操作符,右边是二元操作符)

                                

转换操作符

当设计一个类型时应该考虑到和其它类型之间的转换,这个其实很重要,将对我们的编码有很大的好处,就像每个类型都会有的一个方法Tostring()一样,我们定义一个int类型,可以很方便的用tostring()方法把

int转换为string,当然也可以转换为其它类型。就像上面的rational一样,如果能将一个int或者double转换为一个rational,就会很方便,反之亦然。

 //有理数
    public sealed class rational
    {
        private int _value = 0;

        public int Value
        {
            get { return _value; }
            set { _value = value; }
        }
        public rational(int value)
        {
            this._value = value;
        }

        public rational(double value)
        {
            this._value =(int)value;
        }
        public rational()
        {

        }

        public int ToInt()
        {
            return _value;
        }
        public double ToDouble()
        {
            return (double)_value;
        }
        public static rational operator+(rational num1,rational num2)
        {
            rational result = new rational(num1.Value+num2.Value);
            return result;
        }

    }

1、调用这些构造器和方法,开发人员可以很方便的将int和double对象转换成rational对象,这将给编程工作带来很多方便。设计类型时,应该认真考虑类型需要支持的转换构造器和方法。

2、int i=10;long j=i;这样的代码我们经常会看到,那么从int类型到long类型的转换为什么就可以隐士的进行呢?这就涉及到了我们的转换操作符,下面我们也为rational定义几个转换操作符。

namespace DoNet.Seven.ConsoleApplicationTest
{
    class Program
    {
        static void Main(string[] args)
        {
            int n = 10;
            rational r1 = n;
            double d=(double)r1;

            Console.WriteLine(r1.Value);
            Console.WriteLine(d.ToString());
            Console.ReadKey();

        }
    }
    //有理数
    public sealed class rational
    {
        private int _value = 0;

        public int Value
        {
            get { return _value; }
            set { _value = value; }
        }
        public rational(int value)
        {
            this._value = value;
        }

        public rational(double value)
        {
            this._value =(int)value;
        }
        public rational()
        {

        }

        public int ToInt()
        {
            return _value;
        }
        public double ToDouble()
        {
            return (double)_value;
        }
        public static rational operator+(rational num1,rational num2)
        {
            rational result = new rational(num1.Value+num2.Value);
            return result;
        }

        public static implicit operator rational(int value)
        {
            return new rational(value);
        }
        public static implicit operator rational(double value)
        {
            return new rational(value);
        }
        public static explicit operator int(rational value)
        {
            return value.ToInt();
        }
        public static explicit operator double(rational value)
        {
            return value.ToDouble();
        }

    }
}

输出的结果是10、10。 我们可以在rational、int、double之间来回转换,是不是觉得挺方便的,在这个过程中,编译器又帮我们做了什么呢?

在C#中,implicit关键字告诉编译器为了生成代码来调用方法,不需要在源代码中进行显示转换,相反,explicit关键字告诉编译器只有在发现了显示转型时,才调用方法。

在implicit或explicit关键字之后,要指定operator关键字告诉编译器该方法是一个转换操作符。在operator之后,指定对象要转换成什么类型。在圆括号内,则指定要从什么类型转换。

C#编译器检测到代码中的转型,并内部生成IL代码来调用rational类型定义的转换操作符方法,如果用反编译器看的话可以发现,转换操作符方法会生成下面这样的代码:

结论

不论是操作符重载还是转换操作符,都是在设计类型是考虑到我们编码方便而设计的,下面我们看下C#中decimal类型中的定义。

时间: 2024-11-13 00:29:24

C#中如何利用操作符重载和转换操作符的相关文章

C++ Primer 学习笔记_26_操作符重载与转换(1)--可重载/不可重载的操作符、成员函数方式重载、友元函数方式重载

C++ Primer 学习笔记_26_操作符重载与转换(1)--可重载/不可重载的操作符.成员函数方式重载.友元函数方式重载 引言: 明智地使用操作符重载可以使类类型的使用像内置类型一样直观! 一.重载的操作符名 像任何其他函数一样,操作符重载函数有一个返回值和一个形参表.形参表必须具有操作符数目相同的形参.比如赋值时二元运算,所以该操作符函数有两个参数:第一个形参对应着左操作数,第二个形参对应右操作数. 大多数操作符可以定义为成员函数或非成员函数.当操作符为成员函数时,它的第一个操作数隐式绑定

C++ Primer 学习笔记_27_操作符重载与转换(2)--++/--运算符重载、!运算符重载、赋值运算符重载 、String类([]、 +、 += 运算符重载)、>>和<<运算符重载

C++ Primer 学习笔记_27_操作符重载与转换(2)--++/--运算符重载.!运算符重载.赋值运算符重载 .String类([]. +. += 运算符重载).>>和<<运算符重载 一.++/--运算符重载 1.前置++运算符重载 成员函数的方式重载,原型为: 函数类型 & operator++(); 友元函数的方式重载,原型为: friend 函数类型 & operator++(类类型 &); 2.后置++运算符重载 成员函数的方式重载,原型为:

C++ Primer 学习笔记_28_操作符重载与转换(3)--成员函数的重载、覆盖与隐藏、类型转换运算符、*运算符重载、-&gt;运算符重载

C++ Primer 学习笔记_28_操作符重载与转换(3)--成员函数的重载.覆盖与隐藏.类型转换运算符.*运算符重载.->运算符重载 一.成员函数的重载.覆盖与隐藏 对于类层次的同名成员函数来说,有三种关系:重载.覆盖和隐藏,理清3种关系,有助于写出高质量的代码. 1.成员函数的重载 重载的概念相对简单,只有在同一类定义中的同名成员函数才存在重载关系,主要特点时函数的参数类型和数目有所不同:但不能出现函数参数的个数和类型均相同,仅仅依靠返回值类型不同来区分的函数,这和普通函数的重载是完全一致

C++ Primer 学习笔记_29_操作符重载与转换(4)--转换构造函数和类型转换运算符归纳、operator new 和 operator delete 实现一个简单内存泄漏跟踪器

C++ Primer 学习笔记_29_操作符重载与转换(4)--转换构造函数和类型转换运算符归纳.operator new 和 operator delete 实现一个简单内存泄漏跟踪器 一.转换构造函数 可以用单个实参来调用的构造函数定义从形参类型到该类型的一个隐式转换.如下: class Integral { public: Integral (int = 0); //转换构造函数 private: int real; }; Integral A = 1; //调用转换构造函数将1转换为In

对操作符的重载和转换操作符--------------c#

这种写法能 自由自在的使用 加减乘除等操作符: 先定义一个类 public sealed class chongzai { public Int32 canshu1; //重载操作符 + ,参数必须包含一个以上当前的类型chongzai. public static Int32 operator +(chongzai s, Int32 c) { return (s.canshu1 + c); } //转换操作符,,,可以用=号,将string转换成 chongzai类型,这个implicit是隐

C++语言学习(八)——操作符重载

C++语言学习(八)--操作符重载 一.操作符重载基础 1.操作符重载的语法 通过operator关键字可以定义特殊的函数,operator本质是通过函数重载操作符. Type operator operatorname(const Type p1, const Type p2) { Type ret; return ret; } 2.友元函数重载操作符 可以将操作符重载函数声明为友元函数. #include <iostream> using namespace std; class Comp

C++解析(17):操作符重载

0.目录 1.操作符重载 2.完善的复数类 3.小结 1.操作符重载 下面的复数解决方案是否可行? 示例1--原有的解决方案: #include <stdio.h> class Complex { int a; int b; public: Complex(int a = 0, int b = 0) { this->a = a; this->b = b; } int getA() { return a; } int getB() { return b; } friend Compl

【C/C++】操作符重载

常见问题 Q1. 下列运算符,在C++语言中不能重载的是( ). A. * B. ?: C. :: D. delete Q2. 编写类String的构造函数.析构函数和赋值函数. Q3. 复制构造函数与赋值运算符的区别是什么? Q4. 下述代码的输出结果是什么? 1 #include <iostream> 2 using namespace std; 3 class X 4 { 5 public: 6 X() { cout << "constructor" &l

【学习】操作符重载

2018/8/21 15:16:56 何为操作符重载? 1. 操作符重载就是为了让原有操作符能够作用于用户定义的类型,例如'+'操作符原来只能用于两侧均为数字或字符串的情况,通过操作符重载可以实现如两个时刻相加求和(类似11:20:00 + 1:25:20). 1 class Time(object): 2 def __init__(self,hour=0,minute=0,second=0): 3 self.hour = hour 4 self.minute = minute 5 self.h