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&lt;T&gt;
- IEqualityComparer
- IEqualityComparer&lt;T&gt;
- IComparable
- IComparable&lt;T&gt;
- IComparer
- IComparer&lt;T&gt;
- IStructuralEquatable
- IStructuralComparable

## There is only 6 if you don't count legacy ones:
- IEquatable&lt;T&gt;
- IEqualityComparer&lt;T&gt;
- IComparable&lt;T&gt;
- IComparer&lt;T&gt;
- 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的主要内容,如果未能解决你的问题,请参考以下文章

测试浮点相等性。 (FE_FLOATING_POINT_EQUALITY)

Subset Equality S

CF1451C String Equality

CF1451C String Equality

CF1451C String Equality

2013年考研英语阅读真题 第4篇 Gender equality