Reputation: 3841
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;
}
Upvotes: 1
Views: 623
Reputation: 3841
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
2 Let generic base inherit from non-generic
public abstract class BaseClass<TExists> : BaseClass
{
}
3 Setup abstract
and static
methods in 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 Implement override in child-classes
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
)
ChildClass childClass;
if (ChildClass.Exists(childClassExists, out childClass))
{
// do things with existing childClass
}
6 Say thanks to InBetween and haim7770
@InBetween, @haim7770 -> Thank you! ;)
Upvotes: 0
Reputation: 32740
Just add a new generic parameter in the Exists
method. 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).
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
Adressing your concern about not being able to assign a ChildInstance
to existing
in the overriden ChildClass.InternalExistsCheck(,)
, yes you can by simply doing:
existing = new T();
If T
is ChildClass
(inferred by the compiler) then you will be creating a ChildClass
instance. Bear in mind though that you are getting a BaseClass<ChildExists>
typed reference, not a ChildClass
one.
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):
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 ofexisting
not being a ChildClass
typed reference (and therefore childClassTypedReference
being null
). There is nothing preventing existing
from being any type extending 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.
Upvotes: 2