运算符重载 hash原理 Equals方法

  • 重载的方法提供转换的实现

->定义隐式转换使用关键字 implicit

->定义显式转换使用关键字 explicit

->转换顺序与定义顺序相同

  ->变量1=变量2  对应参数 类型1(类型2 value)

->语法:

[访问修饰符] static[implicit[explicit]] Operator 目标类型(待转换类型 value)

{

  目标类型 0=new 目标类型();

  //赋值操作,显示操作可以将赋值操作用checked{}块包起来,如放不下,就异常

  return 0;

}

 class Program
    {
        static void Main(string[] args)
        {
            Person p = new Person();
            Person p1 = new Person();
            p1.Age = 25;
            p.Age = 34;
            int num1 = p;
            int num2 = p + p1;

        }
    }
    class Person
    {
        public int Age
        {
            set;
            get;
        }
        public static implicit operator int(Person p){
            return p.Age;
        }
        public static int operator +(Person p1, Person p2)
        {
            return p1.Age + p2.Age;
        }
    }

  • string字符串

string的常用方法前面博客已有记载,此处补充说明,string类的比较方法

-》==单个字符进行比较

-》Equal() 可以进行控制的比较。

   bool <object>.Equals(object o);

   bool<string>.Equals(string str);

   bool string.Equals(string str1,string str2)

   int string.Compare(string str1,string str2);

用反编译工具查看String。Equals()

其中object.ReferenceEquals(this,obj)表示比较地址

return EqualsHelper(this,strB);里面是逐个字符比较

 string str1 = new string(new char[] { 'a', 'b', 'c' };
 string str2 = "abc";
 string str3 = "abc";
 Console.WriteLine(str1.Equals(str2));//结果为true
 Console.WriteLine(str2.Equals(str3));//结果为True
 Console.ReadKey();

str2与str3内存地址相同(string字符串拘留池),故两个str1与str2相等。str1与str2内存地址不同,但结果还是为true,二者相等,这事因为string.Equals()方法已经重写object的Equal()方法。重写的Equals()方法内部有个EqualsHelper(this,strB)方法,该方法在判断二者的地址不相同,且二者都部位null对象的时候执行。遍历字符串的每个字符,逐个比较。


hashtable实现的原理简介:

  class Program
    {
        static void Main(string[] args)
        {
            ZQHash h = new ZQHash();
            h.Add("张三", 19);
            h.Add("王五", 29);
        }
    }
    class ZQHash
    {
        object[] keys = new object[255];
        object[] values = new object[255];
        public void Add(object k, object value)
        {
            //调用object的GetHashCode得到一个数字作为索引
            int index = Math.Abs(k.GetHashCode() % 256);//此处需要考虑若生成重复的数字索引的情况
            keys[index] = k;
            values[index] = value;
        }
        public object this[object key]
        {
            get {
                int index = Math.Abs(key.GetHashCode() % 256);
                return values[index];
            }
        }
    }

 Contains()方法

 ArrayList list = new ArrayList();
 int[] nums = { 1, 2, 3, 1, 4 };
 list.AddRange(nums);
 if (list.Contains(3))
 {
     Console.WriteLine("包含数字3");
 } 
         ArrayList list2 = new ArrayList();
         string str = "abc";
         string str1 = new string(new char[] { 'a', 'b', 'c' });
         string str2 ="abc";
         list2.Add(str);
         Console.WriteLine(list2.Contains(str1));//结果为true
         // 因为contains里的Equals()方法是重写了object的Equals(),逐个比较字符串里的每个字符
      Console.WriteLine(str2.Contains(str2));//结果为true
   ArrayList list1 = new ArrayList();
   Person p1 = new Person("王五", '', 26);
   Person p2=new Person("李四",'',29);
   Person p3 = new Person("王五",'',26);
   list1.Add(p1);
   list1.Add(p2);
   if (list1.Contains(p3))//结果为不存在王五
  {
       Console.WriteLine("存在王五");
   }
   else
   {
        Console.WriteLine("不存在王五");
   } 
    Console.ReadKey();

用反编译工具查看Contains()方法内部:

 内部的Equal()方法是继承自object的。object的Equals()方法比较的是地址。因为p3和p1虽然内部数据相等,但二者的指向的地址不一样,所以结果为不存在王五。

若想要程序认为p1和p3相等,我们需要重写object的Equals()方法。

在Person类里定义Equals()重写方法

    public override bool Equals(object obj)
        {
            Person p = obj as Person;
            if (p==null)
            {
                return false;
            }
            if (object.ReferenceEquals(this,p))//比地址不要用等号,因为==可能会有运算符重载的情况
            {
                return true;
            }
            return this.Age == p.Age && this.Gender == p.Gender && this.Name == p.Name;
        }
  •  Hashtable的遍历
namespace Foreach遍历的原理
{
    /// <summary>
    /// 定义一个集合类,并实现IEnumerable接口,以使得它可以用foreach遍历
    /// </summary>
    class ZQCollection:IEnumerable
    {
        ArrayList list;//定义一个线性集合的字段
        public ZQCollection()//构造函数,用来初始化线性集合的字段
        {
            list = new ArrayList();
        }
        public object this[int index]//定义一个索引器,以使得该集合类可以当作数组来使用
        {
            get
            {
                return list[index];
            }
            set
            {
                list[index] = value;
            }
        }
        public int Count//定义一个Count属性,以使得该类像集合一样拥有Count属性
        {
            get { return list.Count; }
        }
        public void Add(object obj)//定义一个Add()方法,以使得该类像集合一样有Add()
        {
            list.Add(obj);
        }
        public IEnumerator GetEnumerator()//定义一个获得实现了IEnumerator接口的枚举器的方法
        {
            return new ZQIEnumerator(list);
        }
        protected class ZQIEnumerator : IEnumerator  //封装一个类,用老作为枚举器,实现接口IEnumerator的所有成员
        {
            int currentIndex = -1;
            ArrayList list;
            public ZQIEnumerator(ArrayList obj)
            {
             this.list = obj;
            }
            public object Current
            {
                get { return list[currentIndex]; }
            }
            public bool MoveNext()
            {
                currentIndex++;
                return currentIndex < list.Count;
            }
            public void Reset()
            {
                throw new NotImplementedException();
            }
        }
    }
}
View Code
namespace Foreach遍历的原理
{
    class Program
    {
        static void Main(string[] args)
        {
            ZQCollection cl = new ZQCollection();
            
            cl.Add("123");//像使用集合一样,给自定义的集合类增加元素
            cl.Add("err");
            cl.Add(120);
            for (int i = 0; i < cl.Count;i++ )//遍历定义集合类
            {
                Console.WriteLine(cl[i]);
            }
          foreach(var temp in cl)//因为该集合类实现了实现了IEnumerable接口,
          { // 里面有一个获得枚举器的方法,有了枚举器,我们就可以用foreach遍历了
              Console.WriteLine(temp);
          }
            Console.ReadKey();
        }
    }
}
View Code

 以上是按从list的正常排序遍历的。我们也可以把枚举器内部设为反序遍历,只需把枚举器内部修改一下,代码如下

   protected class ZQIEnumerator : IEnumerator  //封装一个类,用老作为枚举器,实现接口IEnumerator的所有成员
        {
            //int currentIndex = -1;
            int currentIndex;
            ArrayList list;
            public ZQIEnumerator(ArrayList obj)
            {
             this.list = obj;
             currentIndex = list.Count;
            }
            public object Current
            {
                get { return list[currentIndex]; }
            }
            public bool MoveNext()
            {
                currentIndex--;
                return currentIndex >=0;
            }
            public void Reset()
            {
                throw new NotImplementedException();
            }
        }
View Code

既然我们知道使用foreach遍历集合的原理了,那么我们就很容易理解以下方式也可以实现遍历

 Hashtable hs = new Hashtable();
 for(int i = 0; i < 10;i++ )
 {
    hs.Add(i, i * 11);
 }
 var item=hs.GetEnumerator();
 while(item.MoveNext())
 {
    DictionaryEntry de = (DictionaryEntry)item.Current;
    Console.WriteLine(de.Key + "-" + de.Value);
 }

或者用for循环遍历

       Hashtable hs = new Hashtable();
       for (int i = 0; i < 10;i++ )
       {
          hs.Add(i, i * 11);
       }
       var item=hs.GetEnumerator();
       for (; item.MoveNext(); )
       {
           DictionaryEntry de1 = (DictionaryEntry)item.Current;
           Console.WriteLine(de1.Key + "---" + de1.Value);
       }

 泛型集合Dictionary与List http://www.cnblogs.com/tobecabbage/p/3484918.html

其他泛型集合:因其他一般泛型集合都可以用Dictionary或List代替,所以便不一一做介绍

其中,Hashset<T>  hash集,表示所有数字不重复的集合 

int[] nums = { 1, 2, 3, 4, 2, 1, 3, 6, 8 };
HashSet<int> hs = new HashSet<int>(nums);//结果为1,2,3,4,6,8
nums= hs.ToArray();
原文地址:https://www.cnblogs.com/tobecabbage/p/3535595.html