运算符重载 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对象的时候执行。遍历字符串的每个字符,逐个比较。
- ArrayList线性集合和Hashtable集合(http://www.cnblogs.com/tobecabbage/p/3479209.html)补充说明:
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(); } } } }
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(); } } }
以上是按从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(); } }
既然我们知道使用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();