markdown Equality .NET
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了markdown Equality .NET相关的知识,希望对你有一定的参考价值。
# Equality in .NET
<p align="center">
<img src="https://vignette.wikia.nocookie.net/freerealmswarriorcats/images/9/9d/110660-glowing-green-neon-icon-alphanumeric-equal-sign.png/revision/latest/scale-to-width-down/480?cb=20140103064347" width="480" />
</p>
## There is 4 methods on **System.Object**:
- static Equals()
- virtual Equals()
- static ReferenceEquals()
- virtual GetHashCode()
## There is 9 Interfaces:
- IEquatable<T>
- IEqualityComparer
- IEqualityComparer<T>
- IComparable
- IComparable<T>
- IComparer
- IComparer<T>
- IStructuralEquatable
- IStructuralComparable
## There is only 6 if you don't count legacy ones:
- IEquatable<T>
- IEqualityComparer<T>
- IComparable<T>
- IComparer<T>
- IStructuralEquatable
- IStructuralComparable
## Default == behaviour:
- ReferenceTypes - ReferenceEquality (** Except Strings **)
- ValueTypes - ValueEquality
## == Behave like that because it emits a <kbd>ceq</kbd> operator when there is no static operator == available
- <kbd>ceq</kbd> - compare equal ( il operator )
- When there is **static bool operator ==** available it will use that
- **static bool operator ==** can be inherited
## Boxing
<pre>
int x = 3;
int y = 3;
Console.WriteLine(x==3); // True
IComparable<int> ic1 = x;
IComparable<int> ic2 = y;
Console.WriteLine(ic1==ic2); // False because x&y were boxed into ref type
</pre>
## String == _is always case sensitive_
<pre>
string s1 = "apple";
string s2 = "Apple";
Console.WriteLine(s1==s2); // False
</pre>
## Making string IgnoreCase comparison
<pre>
string s1 = "apple";
string s2 = "Apple";
Console.WriteLine(s1.Equals(s2, StringComparison.OrdinalIgnoreCase)); // True
</pre>
## Float precision
<pre>
float six = 6.000_000_0f;
float nearlySix = 6.000_000_1f;
Console.WriteLine(six==nearlySix); // True
</pre>
## Float rounding
<pre>
float x = 5.05f;
float y = 0.95f;
float z = x + y;
Console.WriteLine(z); // 6
Console.WriteLine(z==6); // False
</pre>
## Float rounding
<pre>
float x = 5.05f;
float y = 0.95f;
float z = x + y;
Console.WriteLine(z); // 6
Console.WriteLine(z==6); // False
</pre>
## virtual Object::Equals has default compare semantics
- referenceTypes refEquality
- valueTypes valEquality
- Exceptions:
- String valEquality
- Delegates valEquality
- Tuples valEquality
## Value types get virtual Equals implementation from System.ValueType it uses reflection to compare all the fields
- System.ValueType.Equals calls Equals() on every field - true if all return true
- Always better to override Equals in structs to avoid reflection implementation
<pre>
public struct Food
private string _name;
public Food(string name)
{
this._name = name;
}
Food banana = new Food("banana");
Food banana2 = new Food("banana");
Console.WriteLine(banana.Equals(banana2)); // True
</pre>
## Static Object.Equals
- If both args == null returns true
- Because static Equals uses instance Equals it will automatically pick up overriden version
<pre>
public static bool Equals(Object obj1, Object obj2){
if (obj1==obj2)
return true;
if (obj1==null || obj2==null)
return false;
else
return obj1.Equals(obj2);
}
</pre>
## == Operator is determined at compile time
<pre>
object s1 = "apple";
object s2 = String.Copy((string)s1);
Console.WriteLine(s1==s2); // False, because compile types of s1 and s2 is Object
</pre>
## Gotcha with generics
<pre>
string s1 = "apple";
string s2 = String.Copy(s1);
DisplayIfArgsAreEqual(s1,s2);
static void DisplayIfArgsAreEqual<T>(T arg1, T arg2) where T:class
{
Console.WriteLine(arg1==arg2); // False, Object == used
}
</pre>
## Implementing ValueType equality example
<pre>
public struct FoodItem:IEquatable<FoodItem>
{
private readonly string _name;
private readonly FoodGroup _group;
public string Name => _name;
public FoodGroup Group => _group;
public FoodItem(string name, FoodGroup group)
{
this._name = name;
this._group = group;
}
public static bool operator ==(FoodItem lhs, FoodItem rhs)
{
return lhs.Equals(rhs);
}
public static bool operator !=(FoodItem lhs, FoodItem rhs)
{
return !lhs.Equals(rhs);
}
public bool Equals(FoodItem other)
{
return _name == other._name && _group == other._group;
}
public override bool Equals(object obj)
{
if (obj is FoodItem foodObj)
return Equals(foodObj);
return false;
}
public override int GetHashCode()
{
return _name.GetHashCode() ^ _group.GetHashCode();
}
public override string ToString()
{
return _name;
}
}
</pre>
## Implementing ReferenceType equality example
<pre>
public class Food
{
private readonly string _name;
private readonly FoodGroup _group;
public String Name => _name;
public FoodGroup Group => _group;
public Food(string name, FoodGroup group)
{
_name = name ;
_group = group;
}
public override string ToString()
{
return _name;
}
public static bool operator ==(Food x, Food y)
{
return Object.Equals(x, y);
}
public static bool operator !=(Food x, Food y)
{
return !Object.Equals(x, y);
}
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (ReferenceEquals(obj, this))
return true;
if (obj.GetType() != this.GetType())
return false;
Food rhs = obj as Food;
return this._name == rhs._name && this._group == rhs._group;
}
public override int GetHashCode()
{
return _name.GetHashCode() ^ _group.GetHashCode();
}
}
public sealed class CookedFood:Food
{
private readonly string _cookingMethod;
public string CookingMethod => _cookingMethod;
public CookedFood(string name, FoodGroup group, string cookingMethod) : base(name, group)
{
this._cookingMethod = cookingMethod;
}
public override string ToString()
{
return String.Format("{0} {1}", _cookingMethod, Name);
}
public static bool operator ==(CookedFood x, CookedFood y)
{
return Object.Equals(x, y);
}
public static bool operator !=(CookedFood x, CookedFood y)
{
return !Object.Equals(x, y);
}
public override bool Equals(object obj)
{
if (!base.Equals(obj))
return false;
CookedFood rhs = obj as CookedFood;
return this._cookingMethod == rhs._cookingMethod;
}
public override int GetHashCode()
{
return base.GetHashCode() ^ _cookingMethod.GetHashCode();
}
}
</pre>
## Comparison convention x.CompareTo(y)
- 0 => x==y
- NegativeNumber => x<y
- PositiveNumber => x>y
## String == uses Ordinal CaseSensitive comparison
## String interning
- String.Copy(s) // return copy
- String.Intern(s) // return shareable instance from pool
<pre>
string s1 = "apple";
string s2 = "app"+"le"; // Compiler optimization
Console.WriteLine(s1==s2); // True
string s3 = "orange";
string s4 = String.Copy(s3); // String.Copy will always copy string without pooling
Console.WriteLine(s3==s4); // False
</pre>
以上是关于markdown Equality .NET的主要内容,如果未能解决你的问题,请参考以下文章