C# 運算符重載


  C#最常見的重載是構造函數重載,各種方法包括ToString()也可以重載,運算符+-*/也可以重載,今天我們就來說說運算符重載。

一、簡介

  C# 允許用戶定義的類型通過使用 operator 關鍵字定義靜態成員函數來重載運算符。注意必須用public修飾且必須是類的靜態的方法。但並非所有內置運算符都可以被重載,詳見表1:

運算符 可重載性
 +、-、!、~、++、--、true、false  可以重載這些一元運算符, true和false運算符必須成對重載
 +、-、*、/、%、&、|、^、<<、>>  可以重載這些二元運算符
 ==、!=、<、>、<=、>=  可以重載比較運算符,必須成對重載
 &&、||  不能重載條件邏輯運算符,但可以使用能夠重載的&和|進行計算
 []  不能重載數組索引運算符,但可以定義索引器
 ()  不能重載轉換運算符,但可以定義新的轉換運算符(請參見 explicit 和 implicit)
 +=、-=、*=、/=、%=、&=、|=、^=、<<=、>>=  不能顯式重載賦值運算符,在重寫單個運算符如+、-、%時,它們會被  隱式重寫
 =、.、?:、->、new、is、sizeof、typeof  不能重載這些運算符

表1

二、聲明

  operator 關鍵字用於在類或結構聲明中聲明運算符。運算符聲明可以采用下列四種形式之一:

  • public static result-type operator unary-operator ( op-type operand )

  • public static result-type operator binary-operator ( op-type operand, op-type2 operand2 )

  • public static implicit operator conv-type-out ( conv-type-in operand )

  • public static explicit operator conv-type-out ( conv-type-in operand )

 

  參數說明:

  result-type:運算符的結果類型。
  unary-operator:下列運算符之一:+ - ! ~ ++ — true false
  op-type:第一個(或唯一一個)參數的類型。
  operand:第一個(或唯一一個)參數的名稱。
  binary-operator:其中一個:+ - * / % & | ^ << >> == != > < >= <=
  op-type2:第二個參數的類型。
  operand2:第二個參數的名稱。
  conv-type-out:類型轉換運算符的目標類型。
  conv-type-in:類型轉換運算符的輸入類型。

  注意:

  1、運算符重載的聲明方式:operator 關鍵字告訴編譯器,它實際上是一個運算符重載,后面是相關運算符的符號。

  2運算符只能采用值參數,不能采用ref或out參數。可參考注意事項一實例。

  3、前兩種形式聲明了用戶定義的重載內置運算符的運算符。op-type 和 op-type2 中至少有一個必須是封閉類型(即運算符所屬的類型,或理解為自定義的類型)。例如,這將防止重定義整數加法運算符。可參考注意事項二實例。

  4、后兩種形式聲明了轉換運算符。conv-type-in 和 conv-type-out 中正好有一個必須是封閉類型(即轉換運算符只能從它的封閉類型轉換為其他某個類型,或從其他某個類型轉換為它的封閉類型)。

  5、對於二元運算符,第一個參數是放在運算符左邊的值,一般命名為lhs;第二個參數是放在運算符右邊的值,一般命名為rhs。

  6、C#要求所有的運算符重載都聲明為publicstatic,必須是類的靜態方法,這表示它們與它們的類或結構相關聯,而不是與實例相關聯

 

    public class Student
    {
        public int Age { get; set; }
        public string Name { get; set; }

        public Student()
        { }

        public Student(int age, string name)
        {
            this.Age = age;
            this.Name = name;
        }
                
        //語法錯誤:ref和out參數在此上下文中無效(去掉ref和out關鍵字即可).
        public static Student operator +(ref Student stu1,out Student stu2)
        {
            return new Student(stu1.Age + stu2.Age, stu1.Name + "+++" + stu2.Name);
        }
    }
注意事項一實例
    public class Student
    {
        public int Age { get; set; }
        public string Name { get; set; }

        public Student()
        { }

        public Student(int age, string name)
        {
            this.Age = age;
            this.Name = name;
        }

        //編譯錯誤:二元運算符的參數之一必須是包含類型(參數c1、c2中有一個類型為Student即可).
        public static Student operator +(int c1, int c2)
        {
            return new Student(c1 + c2, "曉菜鳥");
        }
    }
注意事項二實例

  

比較運算符的重載:

  a、C#要求成對重載比較運算符,如果重載了==,也必須重載!=,否則會產生編譯錯誤。

  b、比較運算符必須返回bool類型的值,這是與其他算術運算符的根本區別。

  c、在重載==和!=時,還應該重載從System.Object中繼承的Equals()GetHashCode()方法,否則會產生一個編譯警告,原因是Equals方法應執行與==運算符相同的相等邏輯。

  d、C# 不允許重載=運算符,但如果重載例如+運算符,編譯器會自動使用+運算符的重載來執行+=運算符的操作。

  e、任何運算符聲明的前面都可以有一個可選的屬性(C# 編程指南)列表。

重點:

  運算符重載其實就是函數重載。首先通過指定的運算表達式調用對應的運算符函數,然后再將運算對象轉化為運算符函數的實參,接着根據實參的類型來確定需要調用的函數的重載,這個過程是由編譯器完成。

public class UserController : Controller
    {
        public ActionResult Index()
        {
            Student student = new Student(18, "博客園");
            var resultOne = student + 3;
            var resultTwo = student + "曉菜鳥";
            return View();
        }
    }

    public class Student
    {
        public int Age { get; set; }
        public string Name { get; set; }

        public Student()
        { }

        public Student(int age, string name)
        {
            this.Age = age;
            this.Name = name;
        }          
     
        public static Student operator +(Student stu, int c2)
        {
            return new Student(stu.Age + c2, stu.Name + "-曉菜鳥");
        }

        public static Student operator +(Student stu, string suffix)
        {
            return new Student(stu.Age + 11, stu.Name + suffix);
        }   
    }
參考實例

 

三、實例

    public class UserController : Controller
    {
        public ActionResult Index()
        {
            string message = string.Empty;
            Student stuA = new Student(1, 18, "曉菜鳥");
            Student stuB = new Student(2, 21, "博客園");
            Student stuC = new Student(1, 23, "攻城獅");
            message = stuA.Name + (stuA == stuC ? "" : "不是") + stuC.Name + "<br />";
            message += stuA.Name + (stuA != stuB ? "不是" : "") + stuB.Name + "<br />";
            message += stuA;
            ViewData.Model = message;
            return View();
        }
    }

    public class Student
    {
        public int Id { get; set; }
        public int Age { get; set; }
        public string Name { get; set; }

        public Student()
        { }

        public Student(int id,int age, string name)
        {
            this.Id = id;
            this.Age = age;
            this.Name = name;
        }

        //重載ToString(),自定義格式化輸出.
        public override string ToString()
        {
            return "編號:" + Id + ";姓名:" + Name + ";年齡:" + Age;
        }
    }

    public class Teacher
    {
        public int Id { get; set; }

        public string Name { get; set; }

        public int Duties { get; set; }

        //重載運算符"+",計算兩個學生的年齡總和.
        public static Student operator +(Student lhs, Student rhs)
        {
            return new Student(0, lhs.Age + rhs.Age, lhs.Name + "" + rhs.Name);
        }

        //重載運算符"-",計算兩個學生的年齡差.
        public static Student operator -(Student lhs, Student rhs)
        {
            return new Student(0, Math.Abs(lhs.Age - rhs.Age), lhs.Name + "" + rhs.Name);
        }

        //重載==運算符,同一Id的學生默認為同一個人.
        public static bool operator ==(Student lhs, Student rhs)
        {
            return lhs.Id == rhs.Id;
        }

        //比較運算符必須成對重載.
        public static bool operator !=(Student lhs, Student rhs)
        {
            return !(lhs == rhs);
        }
    }
運算符重載實例一

 

  編譯"運算符重載實例一"將產生錯誤,錯誤信息:二元運算符的參數之一必須是包含類型。這里的錯誤跟我們上面的"注意事項二實例"的錯誤大同小異,因為在Teacher類中,他不知道Student是什么,只有Student自己知道。只有Student才能決定自己能不能"+-",而不能讓別人決定。operator + 相當於一個函數,我們可以這樣去理解,operator +(op-type operand, op-type2 operand2) 等於 op-type.operator +(operand,operand2) 或者 op-type2.operator +(operand,operand2)。

        public ActionResult Index()
        {
            string message = string.Empty;
            Student stuA = new Student(1, 18, "曉菜鳥");
            Student stuB = new Student(2, 21, "博客園");
            Student stuC = new Student(1, 23, "攻城獅");
            message = stuA.Name + (stuA == stuC ? "" : "不是") + stuC.Name + "<br />";
            message += stuA.Name + (stuA != stuB ? "不是" : "") + stuB.Name + "<br />";
            Student stuSum = stuA + stuC;
            Student stuDiffe = stuA - stuB;
            message += stuSum.Name + "的年齡總和為:" + stuSum.Age + "<br />";
            message += stuDiffe.Name + "的年齡差為:" + stuDiffe.Age + "<br />";
            message += stuA;
            ViewData.Model = message;
            return View();
        }
    }

    public class Student
    {
        public int Id { get; set; }
        public int Age { get; set; }
        public string Name { get; set; }

        public Student()
        { }

        public Student(int id,int age, string name)
        {
            this.Id = id;
            this.Age = age;
            this.Name = name;
        }

        //重載運算符"+",計算兩個學生的年齡總和.
        public static Student operator +(Student lhs, Student rhs)
        {
            return new Student(0, lhs.Age + rhs.Age, lhs.Name + "" + rhs.Name);
        }

        //重載運算符"-",計算兩個學生的年齡差.
        public static Student operator -(Student lhs, Student rhs)
        {
            return new Student(0, Math.Abs(lhs.Age - rhs.Age), lhs.Name + "" + rhs.Name);
        }

        //重載==運算符,同一Id的學生默認為同一個人.
        public static bool operator ==(Student lhs, Student rhs)
        {
            return lhs.Id == rhs.Id;
        }

        //比較運算符必須成對重載.
        public static bool operator !=(Student lhs, Student rhs)
        {
            return !(lhs == rhs);
        }

        //重載ToString(),自定義格式化輸出.
        public override string ToString()
        {
            return "編號:" + Id + ";姓名:" + Name + ";年齡:" + Age;
        }
    }

    public class Teacher
    {
        public int Id { get; set; }

        public string Name { get; set; }

        public int Duties { get; set; }
    }
運算符重載實例二

 

  "運算符重載實例二"是完全沒有問題的,這個時候我們想一個問題,將如我們的Teacher類也涉及到求教師年齡的總和和差值怎么辦?難道只能重寫一遍?不知道您有什么好的思路和見解,不妨在評論里面留下您的看法!請多多指教,曉菜鳥不勝感激!

 

  我這里想到的就是繼承,讓子類去繼承父類的重載!請看"運算符重載實例三"。

 

    public class UserController : Controller
    {
        public ActionResult Index()
        {
            string message = string.Empty;
            Teacher teaA = new Teacher(11, 30, "劉主任", "教導室主任");
            Teacher teaB = new Teacher(12, 45, "呂老師", "校長助理");
            Teacher teaC = new Teacher(11, 27, "劉老師", "小二班班主任");
            Student stuOne = new Student(1, 18, "曉菜鳥");
            Student stuTwo = new Student(2, 21, "博客園");
            Student stuThree = new Student(1, 23, "攻城獅");
            message = stuOne.Name + (stuOne == stuThree ? "" : "不是") + stuThree.Name + "<br />";
            message += stuOne.Name + (stuOne != stuTwo ? "不是" : "") + stuTwo.Name + "<br />";
            message += string.Format("{0}和{1}的年齡總和為:{2}<br />", stuOne.Name, stuThree.Name, stuOne + stuThree);
            message += string.Format("{0}和{1}的年齡差為:{2}<br />", stuOne.Name, stuTwo.Name, stuOne - stuTwo);
            message += stuOne;
            ViewData.Model = message;
            return View();
        }
    }

    public class Student:People
    {
        public Student()
        { }

        public Student(int id,int age, string name)
        {
            this.Id = id;
            this.Age = age;
            this.Name = name;
        }

        //重載ToString(),自定義格式化輸出.
        public override string ToString()
        {
            return "編號:" + Id + ";姓名:" + Name + ";年齡:" + Age;
        }
    }

    public class Teacher:People
    {
        /// <summary> 職務 </summary>
        public string Duties { get; set; }

        public Teacher() { }

        public Teacher(int id, int age, string name, string duties)
        {
            this.Id = id;
            this.Age = age;
            this.Name = name;
            this.Duties = duties;
        }
    }

    //abstract:抽象類用做基類,不能被實例化,用途是派生出其他非抽象類.
    public abstract class People
    {
        public int Id { get; set; }
        public int Age { get; set; }
        public string Name { get; set; }

        //重載運算符"+",計算年齡總和.
        public static int operator +(People lhs, People rhs)
        {
            return lhs.Age + rhs.Age;
        }

        //重載運算符"-",計算年齡差.
        public static int operator -(People lhs, People rhs)
        {
            return Math.Abs(lhs.Age - rhs.Age);
        }

        //重載==運算符,Id相同則視為相等.
        public static bool operator ==(People lhs, People rhs)
        {
            return lhs.Id == rhs.Id;
        }

        //比較運算符必須成對重載.
        public static bool operator !=(People lhs, People rhs)
        {
            return !(lhs == rhs);
        }
    }
運算符重載實例三

 

 

 

"運算符重載實例三"運行結果圖:

運算符重載實例圖 

  關於運算符重載的內容就先介紹到這里,下一篇博客可能會寫關於類型轉換重載方面的問題,加油,曉菜鳥


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM