class a
{static void main()
{a b=new a();
a c=new a();if(b==c)
{代码}}
}为什么我没给自定义类a提供运算符==,就可以用了?如果是object提供的运算符让a继承了,为什么自定义的结构就不能用==运算符呢?结构也是从object继承的啊
如果不是从object继承的==,那自定义类怎么就能用了呢?
{static void main()
{a b=new a();
a c=new a();if(b==c)
{代码}}
}为什么我没给自定义类a提供运算符==,就可以用了?如果是object提供的运算符让a继承了,为什么自定义的结构就不能用==运算符呢?结构也是从object继承的啊
如果不是从object继承的==,那自定义类怎么就能用了呢?
值类型不是直接通过object继承,而是通过valuetype类型继承
Equals 和相等运算符 (==) 的实现准则 下面的规则概括了 Equals 方法和等号运算符 (==) 的实现准则: 每次实现 Equals 方法时都实现 GetHashCode 方法。这可以使 Equals 和 GetHashCode 保持同步。每次实现相等运算符 (==) 时,都重写 Equals 方法,使它们执行同样的操作。这样,使用 Equals 方法的基础结构代码(如 Hashtable 和 ArrayList)的行为就与用相等运算符编写的用户代码相同。每次实现 IComparable 接口时都重写 Equals 方法。实现 IComparable 时,应考虑实现相等 (==)、不相等 (!=)、小于 (<) 和大于 (>) 运算符的运算符重载。不要在 Equals、GetHashCode 方法或相等运算符 (==) 中引发异常。有关 Equals 方法的相关信息,请参见实现 Equals 方法。在值类型中实现相等运算符 (==)
大多数编程语言中都没有用于值类型的默认相等运算符 (==) 实现。因此,只要相等有意义就应该重载相等运算符 (==)。 应考虑在值类型中实现 Equals 方法,这是因为自定义实现会执行,但 System.ValueType 的默认实现不会执行。每次重写 Equals 方法时都实现相等运算符 (==)。在引用类型中实现相等运算符 (==)
大多数语言确实为引用类型提供默认的相等运算符 (==) 实现。因此,在引用类型中实现相等运算符 (==) 时应小心。大多数引用类型(即使是实现 Equals 方法的引用类型)都不应重写相等运算符 (==)。如果类型是 Point、String、BigNumber 等基类型,则应重写相等运算符 (==)。每当考虑重载加法 (+) 和减法 (-) 运算符时,也应该考虑重载相等运算符 (==)。对于预定义的值类型,如果操作数的值相等,则相等运算符 (==) 返回 true,否则返回 false。对于 string 以外的引用类型,如果两个操作数引用同一个对象,则 == 返回 true。对于 string 类型,== 比较字符串的值。默认情况下,运算符 == 通过判断两个引用是否指示同一对象来测试引用是否相等,因此引用类型不需要实现运算符 == 就能获得此功能。当类型不可变时,意味着实例中包含的数据不可更改,此时通过重载运算符 == 来比较值是否相等而不是比较引用是否相等可能会很有用,因为作为不可变的对象,只要它们具有相同的值,就可以将它们看作是相同的。建议不要在非不可变类型中重写运算符 ==。
{
public int age;
public string name;
public static bool operator == (a a1, b b1)
{
return a1.Equals(b1);
}
public static bool operator !=(a a1, b b1)
{
return !(a1.age == b1.age_copy && a1.name == b1.name_copy);
}
}
public class b
{
public int age_copy;
public string name_copy;
public static bool operator ==(b b1, a a1)
{
return b1.Equals(a1);
}
public static bool operator !=(b b1, a a1)
{
return !b1.Equals(a1);
}
}
类是从Object继承的,结构不是从Object继承的。我刚开始学的时候也没无知到这个程度,劝你们多看书,少发言
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
RuntimeType type = (RuntimeType) base.GetType();
RuntimeType type2 = (RuntimeType) obj.GetType();
if (type2 != type)
{
return false;
}
object a = this;
if (CanCompareBits(this))
{
return FastEqualsCheck(a, obj);
}
FieldInfo[] fields = type.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < fields.Length; i++)
{
object obj3 = ((RtFieldInfo) fields[i]).InternalGetValue(a, false);
object obj4 = ((RtFieldInfo) fields[i]).InternalGetValue(obj, false);
if (obj3 == null)
{
if (obj4 != null)
{
return false;
}
}
else if (!obj3.Equals(obj4))
{
return false;
}
}
return true;
}
默认情况下,运算符“==”通过判断两个引用是否指示同一对象来测试引用是否相等,因此引用类型不需要实现运算符“==”就能获得此功能。
我猜测,如果底层代码通过判断引用来得出默认的“==”返回值,那对自定义值类型大都会返回false,这就违背了“==”操作符的初衷。所以微软从编译环节做了限定。并不是底层代码实现不了值类型的引用判断,也不是ValueType做了阻止,实际上我们根本找不到ValueType的源码中有这种东西。 “==”和 Equals() 和 ReferenceEquals(),他们究竟是怎样一种关系呢?
我们可以下载个 Reflector 反编译一下 object 看看。using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.CompilerServices;class Program
{
static void Main(string[] args)
{
object a = new object();
object b = new object();
Console.WriteLine(a == b); // False
Console.WriteLine(object.ReferenceEquals(a, b)); // False
Console.WriteLine(object.Equals(a, b)); // False
Console.WriteLine(a.Equals(b)); // False
b = a;
Console.WriteLine(a == b); // True
Console.WriteLine(object.ReferenceEquals(a, b)); // True
Console.WriteLine(object.Equals(a, b)); // True
Console.WriteLine(a.Equals(b)); // True
}
}// Reflector 反编译出的 Object 部分代码
public class Object
{
// 实例对象的默认 Equals() 是调用底层方法 InternalEquals() 得到的结果
public virtual bool Equals(object obj)
{
return InternalEquals(this, obj);
} // 派生类如果重载“==”操作符,或重写动态方法 Equals(),都会影响到基类 Object 的静态方法 Equals()
public static bool Equals(object objA, object objB)
{
return ((objA == objB) || (((objA != null) && (objB != null)) && objA.Equals(objB)));
} // 参数 MethodImplOptions.InternalCall 指定一个内部调用。内部调用是对在公共语言运行库本身内部实现的方法的调用。
[MethodImpl(MethodImplOptions.InternalCall)]
// 这个方法的源码看不到,不过可以肯定是通过CLR底层代码判断引用的方法。从上面运行结果也可以明确得出这个结论。
internal static extern bool InternalEquals(object objA, object objB); // 注意:没有找到与“==”相关的任何实现代码。所以猜测“==”是类似 InternalEquals() 的。
// 或许还更底层的代码实现的,至少比 Object 的定义更底层,所以绝对不是 Object 实现了所有类的默认“==”。 // 基类 Object 的静态方法 ReferenceEquals(),它调用“==”,而非“==”调用它。
public static bool ReferenceEquals(object objA, object objB)
{
return (objA == objB);
}
}