简体   繁体   English

在抽象基类中使用具体实现的类型

[英]Use type of concrete implementation in abstract base 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). 因为我在这里不需要实例(该实例隐藏在Exists的基类实现中)。

Update #1 更新#1

As implemented like in InBetweens first answer I now have: 正如InBetweens的第一个答案中所实现的那样,我现在有:

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 但这将在ExistsInternal方法的具体实现内引发错误

Cannot convert source type 'ChildClass' to target type 'T' 无法将源类型“ ChildClass”转换为目标类型“ T”

in override 优先

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

Just add a new generic parameter in the Exists method. 只需在Exists方法中添加一个新的通用参数即可。 This type will be inferred by the compiler so there is no real impact in usability: 该类型将由编译器推断,因此对可用性没有实际影响:

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

Note that if you don't change the protected Exists method, you'll get an ambigous call compile time error (VS 2013). 请注意,如果不更改受保护的Exists方法,则会收到模棱两可的调用编译时错误(VS 2013)。

Now, its perfectly fine to do: 现在,这样做非常好:

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

and

ChildClass existing;

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

UPDATE UPDATE

Adressing your concern about not being able to assign a ChildInstance to existing in the overriden ChildClass.InternalExistsCheck(,) , yes you can by simply doing: 解决您担心无法将ChildInstance分配给重写的ChildClass.InternalExistsCheck(,)中的existing对象的担忧,是的,只需执行以下操作即可:

existing = new T();

If T is ChildClass (inferred by the compiler) then you will be creating a ChildClass instance. 如果TChildClass (由编译器推断),则将创建一个ChildClass实例。 Bear in mind though that you are getting a BaseClass<ChildExists> typed reference, not a ChildClass one. 请记住,尽管您正在获取BaseClass<ChildExists>类型的引用,而不是ChildClass类型的引用。

If you absolutely need a ChildClass typed reference then there is a workaround (if you need to do this, its probably because generics is not the right tool for you): 如果您绝对需要一个ChildClass类型的引用,那么可以采取一种解决方法(如果您需要这样做,可能是因为泛型不是您的正确工具):

var childClassTypedReference = (object)existing as ChildClass.

Do realize that the whole solution is not as type safe as you'd maybe wish; 要意识到整个解决方案并不像您希望的那样安全。 you must consider the possibility of existing not being a ChildClass typed reference (and therefore childClassTypedReference being null ). 必须考虑是否existing不属于ChildClass类型的引用(因此childClassTypedReferencenull )的可能性。 There is nothing preventing existing from being any type extending BaseClass<ChildExists> . 没有什么可以阻止existing扩展BaseClass<ChildExists> 任何类型。

I don't have the whole picture of your code but I really think you are misusing generics here. 我没有代码的全貌,但我真的认为您在这里滥用泛型。 I think a non generic approach with an IExists interface dependency would be a much cleaner approach. 我认为具有IExists接口依赖项的非通用方法将是一种更IExists方法。

Inspired by the comments/answers I came up with the following solution which perfectly fits my needs. 受到评论/答案的启发,我想出了以下完全适合我需要的解决方案。

1 Added a new (non-generic) base-class BaseClass 1添加了一个新的(非通用)基类BaseClass

2 Let generic base inherit from non-generic 2让通用库继承非通用库

public abstract class BaseClass<TExists> : BaseClass
{
}

3 Setup abstract and static methods in BaseClass<TExists> 3在BaseClass<TExists>设置abstractstatic方法

// 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 Implement override in child-classes 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 Call it (with types inferred from usage through ChildClass ) 5调用它(通过ChildClass使用推断类型)

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

6 Say thanks to InBetween and haim7770 6感谢InBetween和haim7770

@InBetween, @haim7770 -> Thank you! @ InBetween,@ haim7770->谢谢! ;) ;)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM