【问题标题】:Returning calling child instance from interface or class从接口或类返回调用子实例
【发布时间】:2017-11-21 15:41:42
【问题描述】:

所以这个问题很明显是一块石头杀死两只鸟(一个设计和代码问题)我有一个基类,它有一个基接口

interface IBase
{
   IBase Method1();
}

abstract class Base : IBase
{
   IBase Method1()
   {
     //do work
     return this;
   }
}

现在是子类

interface IChild1 : IBase
{
  IChild1 ChildMethod();
}

class Child1 : Base, IChild1
{
  public IChild1 ChildMethod()
  {
    //do work 
    // this would work fine Method1(); ChildMethod2();
    //but I want to chain methods
    Method1().ChildMethod2();
    return this;
  }

  void ChildMethod2()
  {
    //do work
  }
}

问题的关键是我希望基类返回子类实例。从方法 ChildMethod() 中的代码可以看出,基类方法 Method1() 返回 IBase 的实例,因此链接 ChildMethod2() 是不可能的。是的,我可以生活而不必链接该方法,但假设这是我唯一的选择。

这是我使用泛型的尝试

interface IBase<T> where T : IBase<T>
{
    T Method1();
}

abstract class Base<T> : IBase<T> where T : Base<T>
{
    public T Method1()
    {
        //do work
        return (T)this;
    }
}

interface IChild1 : IBase<IChild1>
{
    IChild1 ChildMethod();
}

class Child1 : Base<Child1>, IChild1
{
    public IChild1 ChildMethod()
    {
        //do work
        Method1(); ChildMethod2();
        return this;
    }

    void ChildMethod2()
    {
        //do work
    }        
}

为了清楚地说明我想要实现的是,对于我对基类(在本例中为接口)进行的每次调用,我都希望返回调用类/接口。 注意:使用 Autofac 进行依赖注入

【问题讨论】:

  • 您的泛型示例不起作用吗?我就是这样做的。你应该可以链接Method1().ChildMethod2();
  • @ChrisPickford 不起作用
  • 你真的需要同时使用接口和父类吗?如果您只有没有接口的继承链会很容易。在这种情况下,泛型对于接口也毫无用处,因为您在使用它们时总是需要指定一些类:IBase&lt;SomeBaseClass&gt;
  • @Evk 我是否使用接口有关系吗?
  • 如果你不使用接口,只使用基类层次结构,你可以以相对清晰的方式做你想做的事。你也可以用接口来做到这一点,但是它的工作方式(使用接口时必须指定类,例如:IChild1&lt;Child1&gt;)会破坏使用这些接口的全部目的,所以这就是为什么我问你是否真的是否需要这些接口。

标签: c# .net inheritance design-patterns


【解决方案1】:

我认为您可以这样做,同时保留这样的接口和基类:

interface IBase<TSelf> where TSelf : IBase<TSelf> {
    TSelf Method1();
}

interface IChild1 : IBase<IChild1> {
    IChild1 ChildMethod();
    void ChildMethod2();
}

class Base<TSelf> : IBase<TSelf> where TSelf : IBase<TSelf> {
    public TSelf Method1() {
        //do work
        // need to double-cast here or just do            
        return (TSelf) (IBase<TSelf>) this;
    }
}

class Child1 : Base<IChild1>, IChild1 {
    public IChild1 ChildMethod() {
        //do work
        Method1().ChildMethod2();
        return this;
    }

    public void ChildMethod2() {
        //do work
    }
}

但正如您在 cmets 中所指出的,这不适用于继承树中的更多成员。如果你可以删除接口,你可以这样做:

public abstract class Base<TSelf> where TSelf : Base<TSelf> {
    public TSelf Method1() {
        //do work
        // need to double-cast here or just do            
        return (TSelf) this;
    }
}

internal class Child1Impl<TSelf> : Base<TSelf> where TSelf : Child1Impl<TSelf> {
    public TSelf ChildMethod() {
        //do work
        Method1().ChildMethod2();
        return (TSelf) this;
    }

    public void ChildMethod2() {
        //do work
    }
}
// create subclass for ease of use, so that caller should not do Child1Impl<Child1> every time
class Child1 : Child1Impl<Child1> {

}

class SubChild1Impl<TSelf> : Child1Impl<TSelf> where TSelf : SubChild1Impl<TSelf> {
    public TSelf SubChildMethod() {
        Method1().ChildMethod();
        return (TSelf) this;
    }
}

class SubChild1 : SubChild1Impl<SubChild1> {

}

那么你可以这样做:

var test = new SubChild1();
test.Method1().ChildMethod().SubChildMethod();

也许你可以用某种方式对接口做同样的事情,但是代码已经相当复杂,使用接口会更加复杂(而且你已经有了基类,所以也许你并不真的需要这些接口)。

【讨论】:

  • 感谢 Evk,但如果我想拥有 Child1 的子类和它的子类,这会是什么样子..
  • 子类化 Child1 将给出 class Child2 : Child1, IChild2... 从而 class Child1 : Base>, IChild1 where T : Child1
  • 是的,对于更多的类,你仍然可以这样做,但是代码会变得太丑而无法考虑。也许它建议您以某种方式重新考虑您的设计。
  • 我想它肯定看起来很难看。那么如果不使用接口,你有什么建议呢?
  • 我已经更新了答案,展示了如何在没有接口的情况下做到这一点。
猜你喜欢
  • 2015-09-20
  • 1970-01-01
  • 1970-01-01
  • 2020-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-28
相关资源
最近更新 更多