C# study notes - operator overloading, interface articles

1. Operator overloading

  • An overloaded operator is a function with a special name, defined by the keyword operator followed by the operator's symbol. Like other functions, overloaded operators have a return type and a parameter list.
  • Syntax:
    public   ~ static   ~  return value type   ~ operator   ~  unary operator   ~ (parameter type   ~ parameter name)
    public   ~ static   ~  return value type   ~ operator   ~  binary operator   ~ (parameter 1 type   ~ Parameter 1 name, parameter 2 type   ~ parameter 2 names)

1. Overloadable and non-overloadable operators

insert image description here

using System;

namespace Day10
{
    
    
    public class Fraction
    {
    
    
        private int num1;
        private int num2;

        public Fraction (int num1,int num2)
        {
    
    
            this.num1 = num1;
            this.num2 = num2;
        }

        public static Fraction operator +(Fraction f1,Fraction f2)//重载+法
        {
    
    
            return new Fraction(f1.num1 + f2.num1, f1.num2 + f2.num2);
        }

        public static bool operator ==(Fraction f1,Fraction f2)
        {
    
    
            if (f1.num1 == f2.num1 && f1.num2 == f2.num2)
                return true;
            return false;
        }

        //委托给==
        public static bool operator !=(Fraction f1,Fraction f2)
        {
    
    
            return !(f1 == f2);
        }

        //判断是否为同一类型,再执行委托
        public override bool Equals(object obj)
        {
    
    
            if (!(obj is Fraction))  //检查对象运行时类型
                return false;
            return this == (Fraction)obj;//比较this == obj ,比较前先将obj强制转换为Fraction
        }

        public override string ToString()//复写Tostring
        {
    
    
            return String.Format("({0},{1})", num1, num2);
        }
    }

    public  class Tester
    {
    
    
        public void Run()
        {
    
    
            Fraction f1 = new Fraction(3, 4);
            Console.WriteLine("f1:{0}",f1.ToString());
            Fraction f2 = new Fraction(5, 6);
            Console.WriteLine("f2:{0}",f2.ToString());
            Fraction f3 = f1 + f2;
            Console.WriteLine("f3:{0}",f3.ToString());
            Fraction f4 = new Fraction(8, 10);
            if(f1==f2)
                Console.WriteLine("f1:{0}==f2:{1}",f1.ToString(),f2.ToString());
            else
                Console.WriteLine("f1:{0}!=f2:{1}", f1.ToString(), f2.ToString());
            if(f4.Equals(f3))
                Console.WriteLine("f4:{0}Equalsf3:{1}",f4.ToString(),f3.ToString());
        }
    }

    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Tester t = new Tester();
            t.Run();
        }
    }
}

Note:
1. If the equal (==) operator is overloaded, the inequality (!=) operator must also be overloaded. Similarly, less than (<) and greater than (>) must be in pairs, and less than or equal to (< =) and greater than or equal to (>=) must be paired.
2. If the equals operator is overloaded, it is recommended to also overload the Equals() method.
3. The comparison operator must return a value of type bool, which is the fundamental difference from other arithmetic operators.
4. Operators can only use value parameters, not ref or out parameters.

2. Conversion operator

  • Implicit and explicit are usually called conversion operators. When the conversion can be successful and no information loss occurs, use the keyword implicit; if there is a risk of losing information, you need to use the keyword explicit.
  • Syntax:
    public   ~ static   ~  implicit   ~  operator   ~  The target type of the conversion operator   ~ (parameter input type   ~ parameter name)
    public   ~ static   ~  explicit   ~  operator   ~  The target type of the conversion operator   ~ (parameter input type   ~ parameter name)
using System;

namespace Day10
{
    
    
    public class Fraction
    {
    
    
        private int num1;
        private int num2;

        public Fraction (int num1,int num2)
        {
    
    
            this.num1 = num1;
            this.num2 = num2;
        }
        //重载构造函数
        public Fraction (int num)
        {
    
    
            this.num1 = num;
            this.num2 = 1;
        }

        //隐式转换整型为Fraction类型,不会发生信息丢失,因此使用implicit
        public static implicit operator Fraction(int num3)
        {
    
    
            return new Fraction(num3);
        }

        //明确(强制)转换Fraction类型为整型,会产生截断值,因此使用explicit
        public static explicit operator int(Fraction f1)
        {
    
    
            return f1.num1 / f1.num2;
        }

        //重载+法
        public static Fraction operator +(Fraction f1,Fraction f2)
        {
    
    
            return new Fraction(f1.num1 + f2.num1, f1.num2 + f2.num2);
        }
        //重载==
        public static bool operator ==(Fraction f1,Fraction f2)
        {
    
    
            if (f1.num1 == f2.num1 && f1.num2 == f2.num2)
                return true;
            return false;
        }

        //委托给==
        public static bool operator !=(Fraction f1,Fraction f2)
        {
    
    
            return !(f1 == f2);
        }

        //判断是否为同一类型,再执行委托
        public override bool Equals(object obj)
        {
    
    
            if (!(obj is Fraction))  //检查对象运行时类型
                return false;
            return this == (Fraction)obj;//比较this == obj ,比较前先将obj强制转换为Fraction
        }

        public override string ToString()//复写Tostring
        {
    
    
            return String.Format("({0},{1})", num1, num2);
        }
    }

    public  class Tester
    {
    
    
        public void Run()
        {
    
    
            Fraction f1 = new Fraction(3, 4);
            Console.WriteLine("f1:{0}",f1.ToString());
            Fraction f2 = new Fraction(5, 6);
            Console.WriteLine("f2:{0}",f2.ToString());
            Fraction f3 = f1 + f2;
            Console.WriteLine("f3:{0}",f3.ToString());
            Fraction f4 = new Fraction(8, 10);
            Fraction f5 = f4 + 4;
            Console.WriteLine("f5:{0}",f5.ToString());
            int num = (int)f5;
            Console.WriteLine("num:{0}",num);
            if(f1==f2)
                Console.WriteLine("f1:{0}==f2:{1}",f1.ToString(),f2.ToString());
            else
                Console.WriteLine("f1:{0}!=f2:{1}", f1.ToString(), f2.ToString());
            if(f4.Equals(f3))
                Console.WriteLine("f4:{0}Equalsf3:{1}",f4.ToString(),f3.ToString());
        }
    }

    class Program
    {
    
    
        static void Main(string[] args)
        {
    
    
            Tester t = new Tester();
            t.Run();
        }
    }
}

2. Interface

  • An interface can only have properties, methods, indexers, and events . There cannot be "fields" (because the interface is not used to store data), and there is no constructor, so you cannot directly use new to instantiate the interface , and the definition of members is the responsibility of the derived class.

  • The difference between an interface and an abstract class:
    1. A C# class can only inherit from a single parent class, but can implement multiple interfaces, that is, a class can only inherit single inheritance, while an interface can implement cross-inheritance (multiple inheritance) ;
    2. When When deriving from an abstract class, all abstract methods in the abstract class must be rewritten; when implementing an interface, every method defined in the interface must be implemented, and an interface cannot be partially implemented;
    3. The inheritance of a class reflects is- a (is one, belongs to) relationship, and the implementation of the interface reflects the able (able) relationship;

  • Interfaces are declared using the interface keyword, which is similar to class declarations. Usually the interface starts with the letter I and ends with able.
    ---- Syntax:
    interface interface name
    { //interface member }

  • The members of the interface cannot add "access modifier", the interface declaration is public by default and cannot be modified.

  • Members in an interface cannot have any implementations ("talking but not doing", just defining a set of unimplemented members).

  • An interface cannot inherit a class, but a class can inherit an interface (an interface can only inherit from an interface, and a class can inherit both an interface and a class)

using System;
using System.Collections.Generic;
using System.Text;

namespace Day10
{
    
    
    interface IFlyable
    {
    
    
       public void Fly();
    }

    abstract class Animal
    {
    
    
        public string Name {
    
     get; set; }

        public Animal(string name) {
    
     this.Name = Name; }

        public abstract void Shout();

        //public abstract void Fly();
    }

     class Dog : Animal
    {
    
    
        public Dog(string name) : base(name) {
    
     }

        public override void Shout()
        {
    
    
            Console.WriteLine("{0}:汪汪",this.Name); 
        }

        //public override void Fly()
        //{
    
    
        //    Console.WriteLine("狗不能飞!");
        //}
    }

    abstract  class Vehicle
    {
    
    

    }

    class Car:Vehicle
    {
    
    

    }

    class Plane:Vehicle,IFlyable
    {
    
    
        public void Fly()
        {
    
    
            Console.WriteLine("飞机正在飞!");
        }
    }

    class Cat : Animal
    {
    
    
        public Cat(string name) : base(name) {
    
     }

        public override void Shout()
        {
    
    
            Console.WriteLine("{0}:喵喵", this.Name);
        }

        //public override void Fly()
        //{
    
    
        //    Console.WriteLine("猫不能飞!");
        //}
    }

    class Duck : Animal,IFlyable
    {
    
    
        public Duck(string name) : base(name) {
    
     }

        public override void Shout()
        {
    
    
            Console.WriteLine("{0}:嘎嘎", this.Name);
        }

        public void Fly()
        {
    
    
            Console.WriteLine("鸭子正在飞!");
        }
    }

    class Bird : Animal,IFlyable
    {
    
    
        public Bird(string name) : base(name) {
    
     }

        public override void Shout()
        {
    
    
            Console.WriteLine("{0}:叽叽喳喳", this.Name);
        }
        public void Fly()
        {
    
    
            Console.WriteLine("鸟儿飞来飞去!");
        }
    }

    class program
    {
    
    
        static void IWant2Fly(IFlyable fly)
        {
    
    
            fly.Fly();
        }

        static void Main()
        {
    
    
            IWant2Fly(new Duck("小黑"));
        }
    }
}

  • Syntax for implementing multiple interfaces:
    access modifier   ~ class   ~  Class name: (parent class,) interface 1, interface 2, interface 3...
    Note: When using multiple interfaces, the methods in each interface must also be implemented.

1. The is and as operators

  • The is operator can query whether an object implements a certain interface (or derives from a certain base class). The operator form is:
    if(expression is type)
    if the expression (must be a reference type, such as an instance of a class) can is safely converted to the type being converted without throwing an exception, and the operator evaluates to true.
  • The as operator performs one more step than the is operator. It tries to convert the object to the type you want to convert, and if an exception is thrown during the conversion process, the as operator returns null.
  • Note: the is operator is slightly weaker than the as operator, so it only needs to do detection but not actually convert. In other cases, the as operator is preferred over the is operator.
using System;
using System.Collections.Generic;
using System.Text;

namespace Day10
{
    
    
    interface IStorable
    {
    
    
        void Read();
        void Write(object obj);
        int Status {
    
     get; set; }
    }

    interface ICompressible
    {
    
    
        void Compress();
        void Decompress();
    }


   public class Note:IStorable
    {
    
    
        private string str;

        public int Status {
    
     get ; set; }

        public Note (string str)
        {
    
    
            this.str = str;
        }

        public override string ToString()
        {
    
    
            return str;
        }

        public void Read()
        {
    
    
            Console.WriteLine("为IStorable接口执行Note类中的Read方法");
        }

        public void Write(object obj)
        {
    
    
            Console.WriteLine("为IStorable接口执行Note类中的Write方法");
        }

    }
   public class Document:Note,ICompressible
    {
    
    
        private int documentID;
        public int ID {
    
     get {
    
     return this.documentID; } }
        public Document(string str,int documentID):base(str)
        {
    
    
            this.documentID = documentID;
        }

        public void Compress()
        {
    
    
            Console.WriteLine("为ICompressible接口执行Document类中的Compress方法");
        }

        public void Decompress()
        {
    
    
            Console.WriteLine("为ICompressible接口执行Document类中的DeCompress方法");
        }
    }

    public class Tester
    {
    
    
        public void Run()
        {
    
    
            string str = "string";
            Note[] myNoteArray = new Note[3];

            for (int i = 0; i < 3; i++)
            {
    
    
                string docText = str + i.ToString();
                if(i%2==0)
                {
    
    
                    Document myDocument = new Document(docText, (i+1)*10);
                    myNoteArray[i] = myDocument;
                }
                else
                {
    
    
                    Note myNote = new Note(docText);
                    myNoteArray[i] = myNote;
                }
            }
            //用is运算符检测Note是否能够安全赋值给一个ICompressible引用
            foreach (var theID in myNoteArray)
            {
    
    
                Console.WriteLine("\nTesting {0} with IS",theID);
                theID.Read(); 
                if(theID is ICompressible)
                {
    
    
                    ICompressible myCompressible = theID as ICompressible;
                    myCompressible.Compress();
                }
                else
                {
    
    
                    Console.WriteLine("This is not compressible!");
                }

                if(theID is Document)
                {
    
    
                    Document myDoc = theID as Document;

                    //清除转换
                    myDoc = theID as Document;
                    Console.WriteLine("my document ID is{0}",myDoc.ID);
                }
            }
            //用as运算符检测Note是否能够安全赋值给一个ICompressible引用
            foreach (var theID in myNoteArray)
            {
    
    
                Console.WriteLine("\nTesting {0} with AS",theID);
                ICompressible myCompressible = theID as ICompressible;
                if(myCompressible!=null)
                {
    
    
                    myCompressible.Compress();
                }
                else
                {
    
    
                    Console.WriteLine("This is not compressible!");
                }

                Document myDoc = theID as Document;
                if(myDoc!=null)
                {
    
    
                    Console.WriteLine("my document ID is{0}",((Document)theID).ID);
                    //额外的括号确保在访问属性前已经完成了转换
                    //Console.WriteLine("my document ID is{0}",myDoc.ID);
                }
                else
                {
    
    
                    Console.WriteLine("this is not a document!");
                }
            }
        }

        static void Main()
        {
    
    
            Tester test = new Tester();
            test.Run();
        }
    }

}

2. Overloading interface methods

  • Both the extension interface and the merge interface can be regarded as the inheritance of the interface;
  • Parent class reference, subclass object : runtime and compile time, member variables and method calls:
    insert image description here
    the following code is the explanation of the above figure:
using System;
using System.Collections.Generic;
using System.Text;

namespace Day10
{
    
    
    class Father
    {
    
    
        public int a = 10;
        public string str = "父类";
        public virtual void Run()
        {
    
    
            Console.WriteLine("这是父类");
        }
    }

    class Son:Father
    {
    
    
        public int a = 5;
        public string str = "子类";
        public override void Run()
        {
    
    
            Console.WriteLine("这是子类");
        }
        public void Stop()
        {
    
    
            Console.WriteLine("子类停止");
        }
    }

    class Test
    {
    
    
        static void Main()
        {
    
    
            Father X = new Son();
            Console.WriteLine("X.a={0}",X.a);  //10
            Console.WriteLine("X.str={0}",X.str);  //父类
            X.Run();   //这是子类
            //X.Stop();  //编译报错
        }
    }
}

  • The code for the overloaded interface is as follows:
using System;
using System.Collections.Generic;
using System.Text;

namespace Day11
{
    
    
    interface IStorable
    {
    
    
        void Read();
        void Write();
    }

    public class Note : IStorable
    {
    
    

        public Note(string str)
        {
    
    
            Console.WriteLine("creating note with:{0}",str);
        }
        //重载接口方法,同时利用虚函数实现多态
        public virtual void Read()
        {
    
    
            Console.WriteLine("为IStorable接口执行父类中的Read方法");
        }
        //重载接口方法,非虚函数
        public void Write()
        {
    
    
            Console.WriteLine("为IStorable接口执行父类中的Write方法");
        }

    }
    public class Document : Note
    {
    
    
 
        public Document(string str) : base(str)
        {
    
    
            Console.WriteLine("creating document with:{0}",str);
        }
        //重载父类的虚方法
        public override void Read()
        {
    
    
            Console.WriteLine("Override执行子类中的Read方法");
        }
        //重写新的、属于自己的Write函数
        public new void Write()
        {
    
    
            Console.WriteLine("执行子类中的新的Write方法");
        }
    }
    class Chongzai
    {
    
    
        public void Run()
        {
    
    
            //通过父类引用子类对象
            Note theNote = new Document("父类引用,子类对象");
            theNote.Read();
            theNote.Write();
            Console.WriteLine("\n");
            //通过接口父类创建的接口引用子类对象
            IStorable isStorable1 = theNote as IStorable;//将父类引用--》接口引用(子类对象并未改变)
            if(isStorable1!=null)
            {
    
    
                isStorable1.Read();//接口引用仍然指向父类,但因为是子类对象,实现时因为多态所以执行子类的方法
                isStorable1.Write();
            }
            Console.WriteLine("\n");
            //子类引用,子类对象
            Document theDoc = new Document("子类引用,子类对象");
            theDoc.Read();
            theDoc.Write();
            Console.WriteLine("\n");
            //子类对象创建的接口
            IStorable isStorable2 = theDoc as IStorable;
            if(isStorable2!=null)
            {
    
    
                isStorable2.Read();//虽然继承了父类的接口,但是子类并没有实现接口,但实现了多态
                isStorable2.Write();//调用的是父类的方法,因为子类的write并不是实现接口的重写或多态
            }
        }

        static void Main()
        {
    
    
            Chongzai test = new Chongzai();
            test.Run();
        }
    }
}

insert image description here
The above code needs to be understood carefully, which involves the realization of polymorphism in the interface, which may not run much in practice.

3. Display interface implementation

  • Displaying the implementation of the interface is to solve the problem of duplicate name of the method
  • Show the syntax for implementing an interface:
    interfaceName.Method()
using System;
using System.Collections.Generic;
using System.Text;

namespace Day12
{
    
    
    interface IStorable
    {
    
    
        void Read();
        void Write();
    }

    interface ITalk
    {
    
    
        void Read();
        void Talk();
    }

    class Document:IStorable,ITalk
    {
    
    
        public Document (string s)
        {
    
    
            Console.WriteLine("creating document with :{0}",s);
        }
        //隐式实现
        public virtual void Read()
        {
    
    
            Console.WriteLine("document read for istorable");
        }

        public void Write()
        {
    
    
            Console.WriteLine("document write for istorable");
        }

        //显示实现     --》        接口名.方法()
        void ITalk.Read()
        {
    
    
            Console.WriteLine("implementing Italk.read");
        }

        public void Talk()
        {
    
    
            Console.WriteLine("implementing Italk.talk");
        }
    }

    class Tester
    {
    
    
        public void Run()
        {
    
    
            Document doc = new Document("test document");
            IStorable istorable = doc as IStorable;
            if(istorable!=null)
            {
    
    
                istorable.Read();
            }

            ITalk italk = doc as ITalk;
            if(italk!=null)
            {
    
    
                italk.Read();
            }

            doc.Read();
            doc.Talk();
        }

        static void Main()
        {
    
    
            Tester test = new Tester();
            test.Run();
        }
    }
}

3. Summary

  • An interface is a contract through which a class can ensure that it implements certain methods, provides certain attributes and indexes, and supports certain events, all of which are described in the interface definition;
  • An instance of an interface cannot be defined . To access interface methods, a class that implements the interface needs to be created;
  • Declaring an interface is similar to declaring a class, but using the keyword interface;
  • In order to implement an interface in a class, you need to use the colon operator, followed by the name of the interface, this syntax is similar to the inheritance syntax;
  • Classes can only derive from one class, but can implement multiple interfaces.
  • If a class has a base class and one or more interfaces, the base class must be placed in the first position (after the colon), and the base class and the interface names are separated by commas ;
  • When defining a class that implements an interface, the class must implement all the members required by the interface;
  • In the interface, it is not allowed to write functions with method bodies, and cannot have fields;
  • The is operator can determine whether an object is derived from a certain class or implements a certain interface. The is operator returns a bool value whether the type conversion is successful, but does not perform the type conversion;
  • The as operator attempts to convert a reference to a base type or interface, and returns null if the type conversion is unsuccessful;
  • An interface can be extended by adding new methods or members. In the new interface definition, use the colon operator, followed by the name of the original interface, which is very similar to derivation between classes;
  • The extended interface contains the original interface, so any class that implements the extended interface must also implement the original interface;
  • The class that implements the interface can mark the methods in the interface as virtual, and then these methods can be overloaded in the derived class to achieve polymorphism;
  • When a class implements two or more interfaces, and there are methods with the same name in different interfaces, in order to resolve conflicts, you can add the interface name and dot operator before the method name. If you do this, you cannot use access modifiers, and these methods are implicitly public methods;
  • Cannot be instantiated: interface, abstract class, static class.

Guess you like

Origin blog.csdn.net/Lcl_huolitianji/article/details/120961843