Item 5: 始终提供ToString()方法。Always Provide ToString()
- 略.中心思想:ToString()几个重写版本,以及一些格式化输出。
Item 6: Understand the Relationships Among the Many
Different Concepts of Equality
Item 6: 了解Equality的不同概念之间的关系。Understand the Relationships Among the Many Different Concepts of Equality
- C#提供了四种检测是否相等的函数。C# provides four different functions that determine whether two different objects are “equal”:
public static bool ReferenceEquals(object left, object right);
public static bool Equals(object left, object right);
public virtual bool Equals(object right);
public static bool operator ==(MyClass left, MyClass right);
- 当你改变了其中的一个方法,会影响到其他的几个。Furthermore, there are relationships among these four functions, so when you change one, you can affect the behavior of the others.
- C#充许你同时创建值类型和引用类型。两个引用类型的变量在引用同一个对象时,它们是相等的,就像引用到对象的ID一样。两个值类型的变量在它们的类型和内容都是相同时,它们应该是相等的。 C# enables you to create both value types and reference types. Two variables of a reference type are equal if they refer to the same object, referred to as object identity. Two variables of a value type are equal if they are the same type and they contain the same contents.
- Object .ReferenceEquals()无法重新定义。它在两个变量引用自同一个对象时返回true,它比较的是对象的引用地址而不是它们的值。这也以为着值类型使用这个方法时总是返回false(这是装箱、拆箱的原因)。Object .ReferenceEquals() returns true if two variables refer to the same object— that is, the two variables have the same object identity. Whether the types being compared are reference types or value types, this method always tests object identity, not object contents. Yes, that means that ReferenceEquals() always returns false when you use it to test equality for value types.
int i = 5;
int j = 5;
if (Object.ReferenceEquals(i, j))
Console.WriteLine("Never happens.");
else
Console.WriteLine("Always happens.");
if (Object.ReferenceEquals(i, i))
Console.WriteLine("Never happens.");
else
Console.WriteLine("Always happens."); - static Object.Equals()无法重新定义。因为它完成了它应该完成的事:在你不知道两个对象的确切类型时断定它们是否是一样的。The second function you’ll never redefine is static Object.Equals().
- 实例的Object.Equals()方法使用对象的ID来断定两个变量是否相等。这个默认的Object.Equals()函数的行为与Object.ReferenceEquals()确实是一样的。但是请注意,值类型是不一样的。System.ValueType并没有重载Object.Equals()。 Object.Equals() method uses object identity to determine whether two variables are equal. The default Object.Equals() function behaves exactly the same as Object.ReferenceEquals(). But wait—value types are different.
- 操作符==()很简单,任何时候你创建一个值类型,重新定义操作符==()。原因和实例的Equals()是完全一样的。默认的版本使用的是引用的比较来比较两个值类型。效率远不及你自己任意实现的一个,所以,你自己写。当你比较两个值类型时,避免装箱操作。.Net框架里的类还是期望引用类型的==操作符还是保留引用类型的语义。operator==() is simple. Anytime you create a value type, redefine operator==(). The reason is exactly the same as with the instance Equals() function. The default version uses reflection to compare the contents of two value types. That’s far less efficient than any implementation hat you would write, so write your own.
- C#给了你多种方法来检测相等性,但你只须要考虑为其中两个提供你自己的方法。你决不应该重载静态的Object.ReferenceEquals()和静态的Object.Equals(),因为它们提供了正确的检测,忽略运行时类型。你应该为了更好的性能而总是为值类型实例提供重载的Equals()方法和操作符==()。当你希望引用类型的相等与对象ID的相等不同时,你应该重载引用类型实例的Equals()。 C# gives you numerous ways to test equality, but you need to consider providing your own definitions for only two of them, along with supporting the analogous interfaces. You never override the static Object.ReferenceEquals() and static Object.Equals() because they provide the correct tests, regardless of the runtime type. You always override instance Equals() and operator==() for value types to provide better performance. You override instance Equals() for reference types when you want equality to mean something other than object identity. Anytime you override Equals() you implement IEquatable<T>.
Item 7:明白GetHashCode()的缺陷 Understand the Pitfalls of GetHashCode()
- 任何对GetHashCode()的重写都必须遵守下面的三个规则:如果两个对象是相等的,那么他们一定会产生相同的哈希值。否则,哈希码无法在容器中找到对象If two objects are equal (as defined by operator==), they must generate the same hash value. Otherwise, hash codes can’t be used to find objects in containers.
- 对于任何对象A,A.GetHashCode()一定是一个实例不变式。无论如何,A.GetHashCode()总是返回相同的值。以此来保证某个“桶”中的对象仍然在这个"桶"中。 For any object A, A.GetHashCode() must be an instance invariant. No matter what methods are called on A, A.GetHashCode() must always return the same value. That ensures that an object placed in a bucket is always in the right bucket.
- 对于任意的输入,哈希函数总是产生一个介于整形内的随机分布。 The hash function should generate a random distribution among all integers for all inputs. That’s how you get efficiency from a hashbased container.