2015-11-12 80 views
1

有没有什么办法可以做到我想要的?而在抽象基类中使用具体实现类型

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

在这里,我们有一些具体的实现:

的基类的定义如下

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

最后我想用它像

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

因为我不需要实例(这隐藏在Exists的基类实现中)。

更新#1

像在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>; 

但是,这将引发一个具体实现ExistsInternal方法的内部错误

无法将源类型'ChildClass'转换为目标类型'T'

在覆盖

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

您必须添加另一个通用参数('TConcrete')。但总的来说,问题意味着糟糕的设计。另外,您可以使用'new TConcrete()'(而不是'Activator.CreateInstance()')(假设您可以添加'new()'约束) – haim770

+0

您是否尝试过'out TExists existingElement '和'TExists temp;'? –

+0

@FabioLuz:'TExists'是包含存在检查数据的对象的基类型,而不是应该返回的对象的类型 - – KingKerosin

回答

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方法,你会得到一个ambigous调用编译时错误(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' 
} 

UPDATE

Adressing有关无法分配一个ChildInstanceexisting在重写你的关注ChildClass.InternalExistsCheck(,),是的,你可以简单地做:

existing = new T(); 

如果TChildClass(由编译器推断),那么你将创建一个ChildClass实例。请记住,虽然您获得了一个BaseClass<ChildExists>键入的参考,而不是ChildClass之一。

如果你绝对需要一个ChildClass类型引用然后有解决方法(如果你需要做到这一点,它可能是因为仿制药是不适合你的工具):

var childClassTypedReference = (object)existing as ChildClass. 

一定要明白,整个解决方案不像您希望的那样安全;你必须考虑existing不是ChildClass键入的参考(因此childClassTypedReferencenull)的可能性。没有任何东西阻止existing任何类型延伸BaseClass<ChildExists>

我没有你的代码的全部图片,但我真的认为你滥用泛型在这里。我认为使用接口依赖的非泛型方法将是一种更简洁的方法。

+0

'default(T)'在这种情况下总是返回'null',你会在下一行获得NRE – haim770

+0

@ haim7770:是的,它的'new T()'。是不是正确的:p谢谢 – InBetween

+0

我仍然有'T'类型的out参数的问题,不能在'InternalClassCheck'的'ChildClass'覆盖中设置。看不到我缺少的东西。 – KingKerosin

0

受意见/答案的启发我提出了以下完全符合我需求的解决方案。

1加一个新的(非通用)基类BaseClass

2让通用基从非通用

public abstract class BaseClass<TExists> : BaseClass 
{ 
} 

3设置abstractstatic方法继承BaseClass<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说感谢在其间并haim7770

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