Use type of concrete implementation in abstract base class

时间:2015-11-12 12:04:40

标签: c# generics inheritance abstract-class

Is there any way to do what I want here?

The base class is defined as follows:

public abstract class BaseClass<TExists>
    where TExists : BaseExists
{
    // needs to be overridden by child
    protected abstract bool Exists(TExists existsData, out /*typeof(this)*/ existingElement); // <- how to have the concrete type here?

    // static method to be invoked without any need of an instance
    public static bool Exists(TExists existsData, out /*typeof(this)*/ existingElement)
    {
        var temp; // <-- how to set the type here?

        // create a concrete instance
        var instance = Activator.CreateInstance(???);

        // call the concrete implementation
        if(instance.Exists(existsData, out temp))
        {
            return true;
        }

        return false;
    }
}

And here we have some concrete implementation:

public class ChildClass : BaseClass<ChildClassExists>
{
    protected override bool Exists(ChildClassExists exists, out ChildClass existingElement)
    {
        // do child-related things here
    }
}

At the end I want to use it like

ChildClass existing;    
if(ChildClass.Exists(new ChildClassExists(), out existing)){
    // do things here with the existing element of type 'ChildClass'
}

because I don't need an instance here (this is hidden inside the base class implementation of Exists).

Update #1

As implemented like in InBetweens first answer I now have:

public static bool Exists<T>(TExists existsModel, out T existingEntityModel)
    where T : BaseClass<TExists>
{
    var instance = Activator.CreateInstance<T>();
    return instance.ExistsInternal(existsModel, out existingEntityModel);
}

protected abstract bool ExistsInternal<T>(TExists createModel, out T existingEntityModel)
    where T : BaseClass<TExists>;

But this will throw an error inside a concrete implementation of the ExistsInternal method

Cannot convert source type 'ChildClass' to target type 'T'

in override

protected override bool ExistsInternal<T>(ChildClassExists existsData, out T existingElement)
{
    existingElement = new ChildClass(); // <-- here the error is thrown
    return true;
}

2 个答案:

答案 0 :(得分:2)

只需在Exists方法中添加新的通用参数即可。这种类型将由编译器推断,因此对可用性没有实际影响:

public abstract class BaseClass<TExists> where TExists : BaseExists
{
    // needs to be overridden by child
    protected abstract bool InternalExistsCheck<T>(TExists existsData, out T existingElement) where T : BaseClass<TExists>, new();

    // static method to be invoked without any need of an instance
    public static bool Exists<T>(TExists existsData, out T existingElement) where T : BaseClass<TExists>, new()
    {
        T temp; // <-- how to set the type here?
        existingElement = null;

        // create a concrete instance
        var instance = new T();

        // call the concrete implementation
        if (instance.InternalExistsCheck(existsData, out temp))
        {
            existingElement = temp;
            return true;
        }

        return false;
    }
}

请注意,如果您未更改受保护的Exists方法,则会收到一个不明确的调用编译时错误(VS 2013)。

现在,完全没问题:

public class ChildClass : BaseClass<ChildClassExists>
{
    protected override bool InternalExistsCheck<T>(ChildClassExists exists, out T existingElement)
    {
        ....
    }
}

ChildClass existing;

if (ChildClass.Exists(new ChildClassExists(), out existing))
{
     // do things here with the existing element of type 'ChildClass'
}

更新

解决您无法在覆盖ChildInstance中分配existingChildClass.InternalExistsCheck(,)的问题,是的,您只需执行以下操作即可:

existing = new T();

如果TChildClass(由编译器推断),那么您将创建一个ChildClass实例。请记住,虽然您获得了BaseClass<ChildExists>类型的引用,但不是ChildClass引用。

如果您确实需要ChildClass类型参考,那么有一种解决方法(如果您需要这样做,可能是因为泛型不适合您):

var childClassTypedReference = (object)existing as ChildClass.

要意识到整个解决方案并不像你想要的那样安全;您必须考虑existing不是ChildClass类型引用的可能性(因此childClassTypedReferencenull)。没有任何内容阻止existing 任何类型扩展BaseClass<ChildExists>

我不了解您的代码的全貌,但我真的认为您在这里滥用了泛型。我认为具有IExists接口依赖性的非泛型方法将是一种更清晰的方法。

答案 1 :(得分:0)

受到评论/答案的启发,我提出了以下完全符合我需求的解决方案。

1添加了一个新的(非泛型)基类BaseClass

2让通用基础继承自非通用

public abstract class BaseClass<TExists> : BaseClass
{
}

abstract

中的3个设置staticBaseClass<TExists>方法
// abstract to be overriden by child-classes
protected abstract BaseClass ExistsInternal(TExists existsModel);

public static bool Exists<T>(TExists existsModel, out T existing) where T : BaseClass<TExists>
{
    // create a new instance of the concrete child
    var instance = (T) Activator.CreateInstance<T>;

    // set the out parameter (can be null)
    existing = instance.ExistsInternal(existsModel) as T;

    // return if already existing
    return existing!= null;
}

4在子类中实现覆盖

protected override BaseClass ExistsInternal(ChildClassExists existsModel)
{
    // check for existing
    var existing = ...; // do child-class dependend stuff

    // return concrete instance or null
    return existing != null ? new ChildClass(existing) : null;
}

5调用它(使用通过ChildClass推断的类型)

ChildClass childClass;
if (ChildClass.Exists(childClassExists, out childClass))
{
    // do things with existing childClass
}

6感谢InBetween和haim7770

  

@InBetween,@ haim7770 - &gt;谢谢! ;)