在抽象基类中使用派生类型

6

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

其中一个方法是一个 Copy 方法,应该在所有派生类中出现,所以我将其放在了基类中。 但是,我希望它返回 派生类型 而不是基类或对象。

我的解决方案是使用类型参数:

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
    }
}

所以,这里的主要目的是移除基类中的类型参数,并仍然使方法返回相应的派生类型。
一个解决方法。
我目前能做到的最好的事情是下面的一条评论,但它仍然使用了一个泛型参数。
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
    }
}

那么你有什么问题? - evanmcdonnal
也许将其实现为通用接口会更好? - Guru Stron
如何在基类中删除类型参数,同时仍使方法返回相应的派生类型。 - Daniel Möller
@Daniel,你应该在基类中创建一个通用的方法,而不是在所有派生类中都定义它。我会给出一个示例方法的答案,它可以像这样工作。 - evanmcdonnal
有趣的是...是否有一种方法可以将类型参数限制为仅派生类型? - Daniel Möller
显示剩余3条评论
4个回答

5

你不能真正做到。基类不可能知道所有未来的实现。你将不得不使用通用的抽象类(就像你所做的那样)类型或通用的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接口的类型,但这将导致运行时错误。如果您对所有派生实现都有绝对控制(即您的抽象类也有一个内部构造函数),那么这不是一个问题。

1
这个解决方案涉及一个中间层,但我认为它更符合您的要求。至少,您可以获得隔离复制代码的可能好处。
    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>
    {
    }

1

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

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

0

你实际上想在基类中实现复制并使其返回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()实现,这是值得努力的。我不知道方法中应该放置什么逻辑,所以我只是模拟了一些东西。此外,我建议通常要查看泛型。它们通常是像这样的最佳选择。如果您的实现需要对基类唯一,请保持相同的方法定义,但将其设置为抽象,然后在基类中进行覆盖。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接