2011-08-13 22 views
10

这是什么我正尝试做一个例子:如何改善这种代码:继承和IEquatable <>

public class Foo : IEquatable<Foo> 
{ 
    public bool Equals(Foo other) 
    { 
     Type type1 = this.GetType(); 
     Type type2 = other.GetType(); 

     if (type1 != type2) 
      return false; 

     if (type1 == typeof(A)) 
     { 
      A a = (A)this; 
      A b = (A)other; 

      return a.Equals(b); 
     } 
     else if (type1 == typeof(B)) 
     { 
      B c = (B)this; 
      B d = (B)other; 

      return c.Equals(d); 
     } 
     else 
     { 
      throw new Exception("Something is wrong"); 
     } 
    } 
} 

public class A : Foo, IEquatable<A> 
{ 
    public int Number1 { get; set; } 
    public int Number2 { get; set; } 

    public bool Equals(A other) 
    { 
     return this.Number1 == other.Number1 && this.Number2 == other.Number2; 
    } 
} 

public class B : Foo, IEquatable<B> 
{ 
    public int Number1 { get; set; } 
    public int Number2 { get; set; } 
    public int Number3 { get; set; } 

    public bool Equals(B other) 
    { 
     return this.Number1 == other.Number1 && this.Number2 == other.Number2 && this.Number3 == other.Number3; 
    } 
} 

但是,正如你可以在上面看到,我不得不使用很多条件语句'如果'来识别真实类型。问题是我必须使用基类。例如:

A a = new A(); 
Foo foo = a; 

foo.Equals(another); 
+0

为什么你首先需要'IEquatable '?这里没有增加任何价值。除了现有的'IEquatable ''实现之外,只要确保子类型(明智地)覆盖'object.GetHashCode'和'object.Equals(object)'。然后您可以免费获得虚拟方法调度,并且可以在更多情况下使用。 – Ani

+0

@Ani你能给我举个例子吗? –

+0

嗯。这些类似乎很奇怪。 Foo的目的是什么,因为它没有任何属性?此外,如果B只是一个多一个数字为什么B不从A继承,只需添加Number3而不是Foo? – alun

回答

1

尝试这段代码:

public class Foo : IEquatable<Foo> 
{ 
    public virtual bool Equals(Foo other) 
    { 
     return true; 
    } 
} 

public class A : Foo,IEquatable<A> 
{ 
    public int Number1 { get; set; } 
    public int Number2 { get; set; } 

    public override bool Equals(Foo other) 
    { 
     if (other.GetType() == typeof(A)) 
     { 
      return Equals((A)other);     
     } 
     throw new InvalidOperationException("Object is not of type A"); 
    } 
    public bool Equals(A other) 
    { 
     return this.Number1 == other.Number1 && this.Number2 == other.Number2; 
    } 
} 

public class B : Foo,IEquatable<B> 
{ 
    public int Number1 { get; set; } 
    public int Number2 { get; set; } 
    public int Number3 { get; set; } 

    public override bool Equals(Foo other) 
    { 
     if (other.GetType() == typeof(B)) 
     { 
      return Equals((B)other); 

     } 
     throw new InvalidOperationException("Object is not of type B"); 
    } 
    public bool Equals(B other) 
    { 
     return this.Number1 == other.Number1 && this.Number2 == other.Number2 && this.Number3 == other.Number3; 
    } 
} 

注意:您可以使用断言功能做类型检查。

+0

看起来很好,在我开始建立像抽象这样的Foo类的开始阶段。我喜欢这种方式,在Foo类中看起来很奇怪,可以将Foo类替换为接口吗? –

+0

继续,选择是你的,我只是提供给你解决方案.... – RockWorld

3

作为一个直接回答你的问题,你似乎实现IEquatable<Foo>总是推迟到(具体)子类的IEquatable<self>实现。这看起来是这样的:

(错误代码,仅用于演示)

// You need to specify what you want when this method is called on a 
// vanilla Foo object. I assume here that Foo is abstract. If not, please 
// specify desired behaviour. 
public bool Equals(Foo other) 
{ 
    if (other == null || other.GetType() != GetType()) 
     return false; 

    // You can cache this MethodInfo.. 
    var equalsMethod = typeof(IEquatable<>).MakeGenericType(GetType()) 
              .GetMethod("Equals"); 

    return (bool)equalsMethod.Invoke(this, new object[] { other }); 
} 

真的不清楚为什么你需要平等的比较总是去“到”基类的IEquatable<self>执行。

该框架已经有虚拟Equals方法,将导致调用相等的方法调用相应的方法。此外,EqualityComparar<T>.Default(大多数收集类型用于进行相等性检查)已经有智慧选择IEquatable<self>.Equals(self)object.Equals(object)视情况而定。

试图在基类中创建一个刚刚转发请求的等式的实现是将无值添加到任何东西,据我所见。

没有关于的进一步解释为什么你需要基类IEquatable<>的实现,我建议只在每种类型上实现正确的等式。例如:

public class A : Foo, IEquatable<A> 
{ 
    public int Number1 { get; set; } 
    public int Number2 { get; set; } 

    public bool Equals(A other) 
    { 
     return other != null 
      && Number1 == other.Number1 
      && Number2 == other.Number2; 
    } 

    public override bool Equals(object obj) 
    { 
     return Equals(obj as A); 
    } 

    public override int GetHashCode() 
    { 
     return Number1^Number2; 
    } 
} 
+0

我想你错过了在你的非泛型等于 – alun

+0

@alun:呼吁,谢谢。固定。 – Ani

0

一种选择是移动数字1和数字2属性的基类,并且仅对比构件添加到子类在子类中平等方法。

class Foo 
{ 
    // move the common properties to the base class 
    public int Number1 { get; set; } 
    public int Number2 { get; set; } 

    public override bool Equals(object obj) 
    { 
     Foo objfoo = obj as Foo; 
     return 
      objfoo != null 
      // require objects being compared to be of 
      // the same derived type (optionally) 
      && this.GetType() == obj.GetType() 
      && objfoo.Number1 == this.Number1 
      && objfoo.Number2 == this.Number2; 
    } 
    public override int GetHashCode() 
    { 
     // xor the hash codes of the elements used to evaluate 
     // equality 
     return Number1.GetHashCode()^Number2.GetHashCode(); 
    } 
} 

class A : Foo, IEquatable<A> 
{ 
    // A has no properties Foo does not. Simply implement 
    // IEquatable<A> 

    public bool Equals(A other) 
    { 
     return this.Equals(other); 
    } 

    // can optionally override Equals(object) and GetHashCode() 
    // to call base methods here 
} 

class B : Foo, IEquatable<B> 
{ 
    // Add property Number3 to B 
    public int Number3 { get; set; } 
    public bool Equals(B other) 
    { 
     // base.Equals(other) evaluates Number1 and Number2 
     return base.Equals(other) 
      && this.Number3 == other.Number3; 
    } 
    public override int GetHashCode() 
    { 
     // include Number3 in the hashcode, since it is used 
     // to evaluate equality 
     return base.GetHashCode()^Number3.GetHashCode(); 
    } 
    public override bool Equals(object obj) 
    { 
     return this.Equals(obj as B); 
    } 
} 
0

我认为派生类不应该在基类中处理。通常,“Foo”对A和B一无所知。

仍然有可能使基本的IEquatable实现为虚拟的,允许A和B重写它并执行它们的特定的相等性检查,即使两个相等检查和检查实例只能用作“Foo”或“Object”。

这会将.Equals(Foo obj)视为Object.Equals(Object obj)的更具体形式。