座谈多少个编制程序习于旧贯,关于操作符重载

 随便写写

1.索引器方法结构大致为<modifier><return type> this [argument list],它可以在接口中定义:  在为接口声明索引器的时候,记住声明只是表示索引器的存在。你只需要提供恰当的访问函数即可,不必包括范围修饰符。以下代码把索引器声明为接口IImplementMe的一部分:

这个操作符重载很有意思

      一个人的成功有时往往体现在细节上,而习惯往往是这些细节的具体表现形式,这里我也想总结几个不太好的编程习惯。

 

interface IImplementMe {  string this[int index]  {  get;  set;  } 

class Program
{
static void Main(string[] args)
{
Person person1 = new Person() { Name = "LiLei", Age = 12 };
Person person2 = new Person("HanMeimei", 11);
Person person3 = person1 person2;
Person person4 = person1 == person2;
Person person5 = 10;
Console.WriteLine($"Name's merge is {person3.Name}nAge's sum is {person3.Age}");
Console.ReadKey();
}
}

      第一:下面的一段程序大概的意思就是,页面上有一个属性HighPrice,它最终会通过ViewState保存在页面中,如果ViewState为空,则设置属性HighPrice的值为-1,否则直接读取ViewState中的值。但实际情况并不是这样,程序在初始化时,如果ViewState["HighPrice"]意外的写入了些非数字字符串数字,程序就会抛出异常。

首先,假设我们有一个Person类型

相应实现的类则必须为IimplementMe的索引器具体定义get和set访问函数。

public class Person
{
public Person() { }
public Person(string name, int age)
{
this.Name = name; this.Age = age;
}
public string Name { get; set; }
public int Age { get; set; }
public static Person operator (Person p1, Person p2)
{
Person p3 = new Person(p1.Name p2.Name, p1.Age p2.Age);
return p3;
}

public int HighPrice {
  get
  {
    if (ViewState["HighPrice"] != null)
       return (int)ViewState["HighPrice"];
    else
       return -1;
  }
   set
   {
       ViewState["HighPrice"] = value;
   }
}

其类型定义如下

索引器可以称之为有参数的属性,它与属性的区别在于属性名称不能相同,不可重载,索引器可以。属性可以使static的,但是索引器必须是实例化的。在我看来索引器的作用在于可以改变现有的一些索引器的索引方式,比如数组的所以方式是以int作为下标,查询相应数据,但是我可以重写索引,使数组的索引以string进行。

public static Person operator ==(Person p1, Person p2)
{
Person p3 = new Person(p1.Name p2.Name, p1.Age p2.Age);
return p3;
}
public static Person operator !=(Person p1, Person p2)
{
Person p3 = new Person(p1.Name p2.Name, p1.Age p2.Age);
return p3;
}

      解决方案:下面给出相对正确的写法。大家如果有更好的写法可以提出参考下。
      说明:(int)ViewState["HighPrice"]这种写法和int.TryParse(ViewState["HighPrice"].ToString(), out _HighPrice);还有是相当大的区别的,因为ViewState["HighPrice"]对象要确保是数字字符串才行,如果不小心给它赋值为空,那么就会出现异常。不要过份相信一个对象的数据类型,特别是这种object类型的,这样写出的程序不健壮。

  class Person
    {
        public string Name { get; set; } = "Person";
        public int Age { get; set; } = 18;

        public Person() { }

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

        public Person(string name) : this(name, 18) { }
        public Person(int age) : this("Person", age) { }


    }

例:

public static implicit operator Person
{
return new Person();
}
}

private int _HighPrice = -1;
        public int HighPrice
        {
            get
            {
                if (null != ViewState["HighPrice"])
                {
                  int.TryParse(ViewState["HighPrice"].ToString(), out _HighPrice);
                }
                return this._HighPrice;
            }
            set
            {
                this._HighPrice = value;
                if (null == ViewState["HighPrice"])
                {
                    this._HighPrice = -1;
                }
                //把变量值保存到ViewState中
                ViewState["HighPrice"] = this._HighPrice;
            }
        }

在正常情况下,我们让两个Person类型相加,是不可能的,例如:

namespace Study
{
    class Program
    {
        static void Main(string[] args)
        {
            ScoreIndex s = new ScoreIndex();
            s["张三", 1] = 90;
            s["张三", 2] = 100;
            s["张三", 3] = 80;
            s["李四", 1] = 60;
            s["李四", 2] = 70;
            s["李四", 3] = 50;
            Console.WriteLine("张三课程编号为1的成绩为:" s["张三",1]);
            Console.WriteLine("张三的所有成绩为:");
            ArrayList temp;
            temp = s["张三"];
            foreach (IndexClass b in temp)
            {
                Console.WriteLine("姓名:" b.Name "课程编号:" b.CourseID "分数:" b.Score);
            }
            Console.ReadKey();
        }
    }
    class IndexClass
    {
        private string _name;
        private int _courseid;
        private int _score;
        public IndexClass(string _name, int _courseid, int _score)
        {
            this._name = _name;
            this._courseid = _courseid;
            this._score = _score;
        }
        public string Name
        {
            get { return _name; }
            set { this._name = value; }
        }
        public int CourseID
        {
            get { return _courseid; }
            set { this._courseid = value; }
        }
        public int Score
        {
            get { return _score; }
            set { this._score = value; }
        }
    }
    class ScoreIndex
    {
        private ArrayList arr;
        public ScoreIndex()
        {
            arr = new ArrayList();
        }
        public int this[string _name, int _courseid]
        {
            get
            {
                foreach (IndexClass a in arr)
                {
                    if (a.Name == _name && a.CourseID == _courseid)
                    {
                        return a.Score;
                    }
                }
                return -1;
            }
            set
            {
                arr.Add(new IndexClass(_name, _courseid, value)); //arr["张三",1]=90
            }
        }
        //重载索引器
        public ArrayList this[string _name]
        {
            get
            {
                ArrayList temp = new ArrayList();
                foreach (IndexClass b in arr)
                {
                    if (b.Name == _name)
                    {
                        temp.Add(b);
                    }
                }
                return temp;
            }
        }
    }
}

 

图片 1

2.操作符重载:

      //第二:对于多条件的判断,最典型的要数&&操作符了。如果一个语句的执行需要同时满足两个条件,我们经常会这样写:if(条件一&&条件二),意图是认为条件一和条件二都等于true的情况下,但实际情况是如果两人条件//都是false,那么最后的条件一&&条件二的结果刚好也是true,此时就会出现不可预测的错误。而且这种错误也是非常难查找的。有时候写代码能省就省,不能省的一个也不能少。

那么如何能让两个Person类型相加,然后返回一个Person类型呢

操作符重载是将现有的一些操作符的功能进行改变,例如两个类相加,相减,相比较等,它提供Operaor关键字进行重载,必须与static关键字联合使用。例:

      //说明: 1:此条对C#不成立,但其它的语言就不一定,大家可以测试下。

例如,我想让名字为"张三"年龄为19的Person加上另一个名字为"李四",年龄为20的Person

namespace ContainerAndOperator
{
    /// <summary>
    /// 索引器,此类已成为容器类,索引器大部分使用在容器类中
    /// 使用IEnumerable与GetEnumerator()目的在于使这个类可以进行foreach
    /// </summary>
    public class ContainerClass : IEnumerable
    {
        private ArrayList people = new ArrayList();
        public Person this[int index]//Person为返回的值类型,int为输入的索引值的类型,this用来定义索引器
        {
            get { return (Person)people[index]; }
            set { people.Insert(index, value); }
        }

               //2:由于此条并不适用于主流的语言,写在这有点让园友糊涂,这里表示道歉,但在某种环境上确实存在,起码我遇到过,这里并不要求大家同意我的观点,信则有不信则无,只有当你真正遇到过才会有更深的体会。

然后返回一个名字为"张三李四",年龄为39的Person

        public IEnumerator GetEnumerator()
        {
            return people.GetEnumerator();
        }
    }

     更新:上面的第二条大家都不太认同,不过我遇到的情况和这篇文章差不多: ,大家可以参考下,有园友说是因为firebug的一个BUG,这里我特把这条注释掉,这里没有像园友说的嘴硬不承认错误,而是有时候的确有些难以解释的现象出现,而且当改变相应的写法后的确原有的BUG不存在。

那么就需要用到重载" "号这个操作符了

    public class Person
    {
        public string name { get; set; }
        public string Id { get; set; }
        public int Age { get; set; }
        /// <summary>
        /// 重构二元操作符
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <returns></returns>
        public static Person operator (Person p1,Person p2)
        {
            return new Person(p1.name "-" p2.name, p1.Id "-" p2.Id, p1.Age p2.Age);
        }
        public static string operator -(Person p1, Person p2)
        {
            return p1.name "-" p2.Id;
        }
        public Person(){}
        public Person(string n,string i,int a)
        {
            name = n;
            Id = i;
            Age = a;
        }
    }
}

      第三:对于if语句的写法。我们大多会这样写:if(条件==true),正常情况下是没有问题,但有时会写成if(条件=true),也就是程序员在写的时候少写了一个等号,造成程序永远执行下面的代码,这种错误查找起来也是相当困难的,因为编译器在编译时并不会报错。

所以,代码就如下,在Person中重载

namespace ContainerAndOperator
{
    class Program
    {
        static void Main(string[] args)
        {
            ContainerClass con = new ContainerClass();
            con[0] = new Person("homer", "11", 11);
            con[1] = new Person("homer1", "12", 12);
            con[2] = new Person("homer2", "13", 13);
            Console.WriteLine(con[2].name);
            foreach(Person s in con)
            {
                Console.WriteLine(s.name);
            }
            Console.WriteLine("*******************************");
            Person p3 = con[1] con[2];
            Console.WriteLine(p3.name);
            Console.WriteLine(con[1] - con[2]);
            Console.ReadLine();
        }
    }
}

      解决方案:
        1:可以这样写if(true==条件),如果你写成了if(true=条件),编译器会报错,因为true是不能充当左值的。
        2:如果只有一个条件,就直接if(条件),把==true给省略即可,如果是多条件就按方法一来执行。

     /// <summary>
        /// 重载 号
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <returns>返回一个Person类型</returns>
        public static Person operator (Person p1,Person p2)
        {
            //将两个相加的Person类型分别让他们的
            //名字和年龄相加后的值赋值给被返回的Person类型
            Person p3 = new Person(p1.Name   p2.Name, p1.Age   p2.Age);
            return p3;
        }

因为有时候我们可能需要对两个类进行对比,已完成一些特定的功能,但是,原生的操作符不支持的情况下,我们就可以重载操作符。

           说明:1:if(条件=true)这种程序当然并不是程序员想这要写,只是有时会少写一个而已。

然后我们就可以在Main中来相加两个Person类型了

                    2:if(条件=true),编译器并不会报错,有园友说会出提示警告,这里大家可以自己取证下。

看图

      第四:对于操作符的重载问题。例如我们想重载“==”,代码如下:两个对象相等的标准就是属性sName相等,程序中一上来就直接p.sName,没有考虑到p对象是否为null,这种也是编译器无法在编译期间判断的。这种代码也只有在程序调试时才比较容易发现,如果你在程序中判断这个自定义类是否为空:if(null==自定义类),我们从程序上来看这里都是不会出问题的,但是在等号重载中没有判断对象的有效性,这对BUG的排查也是相当困难的。

图片 2

              说明:这里重载了等号和不等号,这里并不是多余的,而是必须,因为它们必须成对出现。

这样就成功了

/// <summary>
    /// 自定义测试类
    /// </summary>
    public class a
    {
        public string sName
        {
            get;
            set;
        }
        public a(string _sName)
        {
            this.sName = _sName;
        }
        /// <summary>
        /// 重载==操作符
        /// </summary>
        /// <param name="p"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool  operator ==(a p, a b)
        {
            if (p.sName == b.sName)
            { return true; }
            else
            { return false; }
        }
        /// <summary>
        /// 重载!=操作符
        /// </summary>
        /// <param name="p"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static bool  operator !=(a p, a b)
        {
            return !Object.Equals(p, b);
           
        }

然后其它的诸如

    }

 

 

而关键点就在于如果你要重载操作符就必须格式如下

       第五:对于数据格式转换。拿字符串转换成数字来说,很多朋友喜欢直接int.Parse(要转换的字符串),如果这个字符串是你期待的数字字符串那没问题,如果字符中为空,或者是存储的中文或者其它非数字字符串,那也是转换失败,其实我们大可利用int.TryParse方法来解决,不成功还有一个默值,起码不能中止程序的运行。

 

       我大概总结了几个,大家看还有没有些类似的不太好的习惯呢?

白话:public static 返回类型 operator被重载的操作符(本类型,要与之操作的类型)

  

正文:public static Person operator (Person p1,Person p2)   => 意思为:我要让两个Person类型相加,然后返回一个Person类型

甚至你可以把返回类型改为int,然后两个Person类型相加后,你返回一个int类型的数据回去

例如返回  p1.Age p2.Age  这样,在将两个Person类型相加之后,将得到一个int类型的数据,其值就是相加的两个Person类型的Age值的相加值

 

还有个要注意的是,

如果你重载了 == 操作符,就必须要重载 != 因为它们是成对,还有其它成对运算符

而且重载了 == 后,还应该重载 Equals,以及GetHashCode

 

===========================================================================================================

 

下面再说说转换操作符

还是说上面的那个Person吧

例如,我非要让

Person p=30;

正常情况下,是不可能的,但如果我这样在Person中写就行了

 public static implicit operator Person(int age)
        {
            return new Person(age);
        }

格式的话,就是固定死的,implicit关键字,如果没记错的话就是代表可以隐式转换

还有个显示转换的,我忘了,不好意思,懒得查资料了

这一段代码的意思就是

我要让一个Person类型的数据,能够给它一个int类型的值

例如

图片 3

 

=============================================================================================

后记:写得比较少,只拣了两个例子去随便说了下,其实自己感觉就这两个例子就够了

其它的自己多尝试,语法格式都是固定死了的,怎么写就看自己的思想有多么天马行空了

好了,最后我们来利用刚才说的东西,去解决一下下面这道题

图片 4

怎么让 

a==1 && a==2 && a==3 =true

怎么做呢,看我们来调皮一下吧

 

首先,我们不管a是什么类型,反正不太可能是int类型,因为不管原始a等于多少,上述表达式似乎都不为true

那么我们自己来建个类型为Rational

我们要做的就一件事

为Rational重载 == 操作符

让它不管与什么int类型的数字比较都返回true  (够调皮吧)

看代码吧:

class Rational
    {
        public int Val { get; set; } = 0;

        public Rational()
        {

        }

        public Rational(int val)
        {
            this.Val = val;
        }

        /// <summary>
        /// 我们重载了==操作符
        /// </summary>
        /// <param name="r"></param>
        /// <param name="val"></param>
        /// <returns></returns>
        public static bool operator==(Rational r,int val)
        {
            //只返回一个true是为了让所有与Rational类型相比对的int类型
            //都返回true
            //因为重载了==,所以必须重载!=
            //其实还应该重载Equals,以及GetHashCode
            //因为它们都是判断相等的类型

            return true;
        }

        public static bool operator !=(Rational r, int val)
        {
            return true;
        }

    }

 

然后在Main中试试吧

 static void Main(string[] args)
        {
            Rational a = new Rational();
            bool result = a == 1 && a == 2 && a == 3;
            Console.WriteLine(result);
            Console.ReadKey();
        }

你会发现,为true,是吧

 

本文由星彩网app下载发布于计算机编程,转载请注明出处:座谈多少个编制程序习于旧贯,关于操作符重载

TAG标签: 星彩网app下载
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。