How to determine if two generic type values are equal?

前端 未结 7 2203
忘掉有多难
忘掉有多难 2021-02-08 13:29

Update* I am so sorry... my sample code contained an error which resulted in a lot of answers I didn\'t understand. In stead of

Console.WriteLin         


        
7条回答
  •  梦谈多话
    2021-02-08 13:45

    As Eric Lippert says in answer to this question - Overload resolution is performed at compile time.

    If you take a look at StringBuilder's implementation you will notice it overloads Equals and does not override it. This is basically the root of the problem as to why StringBuilder.Equals does not work as you expected in your example.

    Take the following 2 classes as example. Overloader is analogous to StringBuilder in the example as it overloads Equals. Overrider is very similar except it it overrides Equals instead.

    public class Overloader
    {
      public string Str {get;private set;}
      public Overloader (string str) {Str = str;}
    
      public bool Equals( Overloader str )
      {
        return this.Str.Equals( str );
      }
    }
    
    public class Overrider
    {
      public string Str {get;private set;}
      public Overrider (string str) {Str = str;}
    
      public override bool Equals( object obj )
      {
        if ( obj is Overrider )
        {
          return this.Str.Equals( (obj as Overrider).Str );
        }
        return base.Equals( obj );
      }
    }
    

    I have slightly modified your GenericObject class in my example:

    class GenericOjbect
    {
      public T Value {get;private set;}
      public GenericOjbect( T val ) {Value = val;}
    
      public bool Equals( T val )
      {
        return Value.Equals( val );
      }
    
      public override bool Equals( object obj )
      {
        if ( obj is T )
        {
          return this.Equals( ( T )obj );
        }
        if (obj != null && obj is GenericOjbect )
        {
          return this.Equals( ( obj as GenericOjbect ).Value );
        }
        return base.Equals( obj );
      }
    }
    

    In this sample program you will see that Overloader (or Stringbuilder for that matter) will return false. However, Overrider returns true.

    class Program
    {
      static void Main( string[] args )
      {
        var goOverloader1 = new GenericOjbect( new Overloader( "StackOverflow" ) );
        var goOverloader2 = new GenericOjbect( new Overloader( "StackOverflow" ) );
    
        var goOverrider1 = new GenericOjbect( new Overrider( "StackOverflow" ) );
        var goOverrider2 = new GenericOjbect( new Overrider( "StackOverflow" ) );
    
        Console.WriteLine( "Overrider  : {0}", goOverloader1.Equals( goOverloader2 ) ); //False
        Console.WriteLine( "Overloader : {0}", goOverrider1.Equals( goOverrider2 ) ); //True
      }
    }
    

    Referencing Eric Lippert again - Overload resolution is performed at compile time. Meaning that the compiler basically looks at your GenericObject.Equals( T val ) like this:

    public bool Equals( T val )
    {
      return Value.Equals( (Object) val );
    }
    

    To anwser your question How to determine if two generic type values are equal?. There's two things you possibly could do.

    1. If you own all the objects that will be wrapped in GenericObject ensure they all at least override Equals.
    2. You could perform some reflection magic in your GenericObject.Equals(T val) to manually perform late binding.

提交回复
热议问题