我可以使用泛型来更改子类的方法签名吗?

时间:2016-07-25 20:03:56

标签: c# generics

我需要对子类执行操作并返回结果:

public interface IEntity { }

public abstract class Entity : IEntity {
  public abstract IEntity doStuff(IEntity e1, IEntity e2, IEntity e3);
}

public class Customer : Entity {
  public override IEntity doStuff(IEntity e1, IEntity e2, IEntity e3) {    // <-- yuck
  var customer1 = e1 as Customer;                                          // <-- yuck
  var customer2 = e2 as Customer;                                          // <-- yuck
  var customer3 = e3 as Customer;                                          // <-- yuck
  // do stuff
  return foo;
  }
}

我想避免使用该子类的方法签名以及相关的类型转换。

所以我更喜欢这个:

public override Customer doStuff(Customer c1, Customer c2, Customer c3) {
  // do stuff
  return foo;
  }

我如何使用类型系统来实现这一目标?

编辑:我将方法的名称从compare更改为doStuff,以重申操作本身无关紧要。我不想比较。我只是想改变类型。我该怎么做?

<小时/> 许多人都说要改变设计,但我做不到。我已经有了一个解决方案,我已经将其包含在下面了,它的确有效。如果您有更好的方法来实现这一点,而不是批评设计(这不是重点),请告诉我。感谢大家的贡献。

3 个答案:

答案 0 :(得分:2)

这很有效。但是自我引用的泛型让我头疼。

public interface IEntity { }

public abstract class Entity<TEntity> : IEntity where TEntity : IEntity {
  public abstract TEntity doStuff(TEntity e1, TEntity e2, TEntity e3);
}

public class Customer : Entity<Customer> {
  public override Customer doStuff(Customer c1, Customer c2, Customer c3) {
    // do stuff
    return foo;
  }
}

这是一个很好的解决方案,还是那里有陷阱会给我带来问题?

有更好的解决方案吗?

答案 1 :(得分:1)

在持续无知,序列化(JSON / XML)和网络传输二值化的前景中,没有接口你可能会更好。

为了区别也称为实体的POCO类,我更喜欢原始术语&#34;域对象&#34;正如埃里克埃文斯所说的那样。原创作品。

这只是我要做的一个例子。

public abstract class AbstractDomainObject<T>
  where T : AbstractDomainObject
{
    public abstract bool CanDoStuffWith(T other);
}

public class Customer : AbstractDomainObject<Customer>
{
    public override bool CanDoStuffWith(Customer other)
    {
        return this.Gender != other.Gender;
    }
}

答案 2 :(得分:1)

这个令人困惑的原因是这个

public abstract class Entity : IEntity {
    public abstract IEntity doStuff(IEntity e1, IEntity e2, IEntity e3);
}

不应该实施IEntity。如果您需要一个使用IEntity“填充”的类,则该类与IEntity分开。这是单一责任原则。除非IEntity的主要目的是doStuff,否则doStuff不会属于同一类。

无论doStuff 做什么,这就是这个课程应该是什么。例如,如果它比较IEntity的实例是否与某些操作兼容,则可以执行以下操作:

public interface ICompatibilityChecker<TEntity> where TEntity : IEntity
{
    bool AreCompatible(TEntity entity, TEntity other);
}

然后你可能会发现你甚至不需要抽象类:

public class CompatibilityChecker : ICompatibilityChecker<Customer>
{
    public bool AreCompatible(Customer entity, Customer other)
    {
        //check compatibility
    }
}

涉及的另一个原则是Favor Composition Over Inheritance。当将功能放入完全独立的类中时,通常更有意义,因此倾向于将功能放入基类中。但请注意,当您将其中一些行为分离到不同的类中时,这些类的设计变得更加简单。

此外,如果您有不需要该行为的域对象,该怎么办?然后继承变得更加困难,因为您可能需要抽象类中的其他方法,但是您仍然无法实现另一个您甚至不需要的方法。

当我们尝试通过让它们从公共基类继承而在类之间共享功能时,它往往会被复杂化并最终崩溃。如果我们将行为和责任分成不同的类,那么维护起来要容易得多。