【问题标题】:Use derived type in base abstract class在基本抽象类中使用派生类型
【发布时间】:2013-06-30 05:13:45
【问题描述】:

好的,我有许多从基类派生的不同类。 这个基类是一个包含常用方法的抽象。

其中一个方法是Copy 方法,它应该存在于所有派生类中,所以,我把它放在了基类中。 但是,我希望它返回 derived type 而不是基础或对象。

为此我得到的解决方案是使用类型参数:

abstract class CopyableClass<T>
{
    public abstract T Copy();
}

class DerivedClass : CopyableClass<DerivedClass>
{
    public override DerivedClass Copy()
    {
        //do what is needed for copy and return a new DerivedClass
    }
}

所以,这里的主要目的是

去掉基类中的类型参数,仍然让方法返回对应的派生类型。


一种解决方法。

到目前为止我能做的最好的事情是下面的 cmets 之一,但它仍然使用通用参数

abstract class BaseClass
{
    //base methods not related to deriving type
}

interface ICopyable<T>
{
     T Copy();
}

class DerivedClass : BaseClass, ICopyable<DerivedClass>
{
    public DerivedClass Copy()
    {
        //do what is needed for copy and return a new DerivedClass
    }
}

【问题讨论】:

  • 那么你的问题是什么?
  • 可能会更好地将其实现为通用接口?
  • 如何去掉基类中的类型参数,仍然让方法返回对应的派生类型。
  • @Daniel 您应该在基类中创建一个通用方法,而不是在所有派生类中定义它。我会用一个像这样工作的示例方法给出答案。
  • 这很有趣...有没有办法将类型参数限制为仅是派生类型?

标签: c# inheritance type-parameter


【解决方案1】:

你真的不能。基类不可能知道所有未来的实现。您将不得不求助于通用抽象类(就像您所做的那样)类型或通用 Copy 方法。

public abstract class CopyableClass
{
    public abstract T Copy<T>() where T : CopyableClass;
}

public class DerivedClass : CopyableClass
{
    public override T Copy<T>()
    {
        if(typeof(T) != typeof(DerivedClass))
            throw new ArgumentException();

        // return your copy
    }
}

或者,如果你想在你的基类中泛化类型检查:

public abstract class CopyableClass
{
    public T Copy<T>() where T : CopyableClass
    {
        if(GetType() != typeof(T))
            throw new ArgumentException();

        return (T) Copy();
    }

    protected abstract CopyableClass Copy();
}

public class DerivedClass : CopyableClass
{
    protected override CopyableClass Copy()
    {
        return // Your copy;
    }
}

请注意,第二种方法非常信任派生类的实现,因为它会盲目地转换抽象方法的返回值。编译器将允许您在派生类型中返回另一种类型,实现 CopyableClass,但这将是运行时错误。如果您对所有派生实现有绝对控制权(即您的抽象类也有一个内部构造函数),这不是问题。

【讨论】:

    【解决方案2】:

    此解决方案涉及中产阶级,但我认为它更符合您的需求。至少您可以获得隔离复制代码的可能好处

        public abstract class BaseClass
        {
        }
    
        public abstract class CopyableClass<T> : BaseClass
            where T: BaseClass, new()
        {
            public T Copy()
            {
                var copy = new T(); // Creating a new instance as proof of concept
    
                return copy;
            }
        }
    
        public class DerivedClass : CopyableClass<DerivedClass>
        {
        }
    

    【讨论】:

      【解决方案3】:

      您实际上想在基类中实现复制并让它返回T。这将使您使用类型参数调用它并返回该类型。

      public static T Copy<T>() where T : CopyableClass
      {
          T retVal = new T();
          // do whatever copying is required
          return retVal;
      }
      

      你可以这么称呼它;

      DerivedClass d = Copy<DerivedClass>();
      

      您实际执行复制的代码可能需要更多的工作才能使通用化,但值得付出努力,因为您将拥有适用于任何派生类型的 Copy() 的单一实现。我不知道该方法中属于什么逻辑,所以我只是将事情排除在外。另外,我建议总体上检查泛型。它们通常是此类事情的最佳选择。如果您的实现需要对基类是唯一的,请保持相同的方法定义,但将其抽象化,然后在基类中覆盖它。

      【讨论】:

        【解决方案4】:

        这将允许您将此基类转换为派生类型并返回它。

        public abstract class BaseClass<TDerived> : where TDerived: BaseClass<TDerived>
        {
           public TDerived DoSomethingCommon(string param)
           {
              var derivedType = (TElement)this;
              //do something.
              return derivedType;
           }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-11-19
          • 2017-06-21
          • 2021-08-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-11
          相关资源
          最近更新 更多