I'm writing a program and found some common behavior, so I thought this would be an appropriate use case for an abstract base class.
This is a simplified version of my Abstract Base Class:
public abstract class BehaviorClass<T> where T: IDomainObj
{
protected BehaviorClass(var x){...}
public abstract void Create(List<T> list, out string message);
public abstract void Delete(List<T> list, out string message);
...
}
This is a simplified version of my Derived Class:
public class DbSheets : BehaviorClass<Sheet>
{
public override void Create(List<Sheet> sheets, out string message){...}
public override void Delete(List<Sheet> sheets, out string message){...}
...
}
This is the Generic Method that I want to operate on my derived classes:
public void Import<DbObj>() where DbObj : BehaviorClass<IDomainObj>
{
var instance = (DbObj)Activator.CreateInstance(typeof(DbObj), DbAccessor);
// STEP 1: Remove existing values
var existingValues = instance.Read();
instance.Delete(existingValues, out message);
// STEP 2: Create new IDomainObjects
var domainObjects = //LINQ Query.ToList();
// STEP 3: Add new IDomainObjects to the instance
instance.Create(domainObjects, message);
}
Up to this point, everything compiles fine until I try to Call the Import Method.
internal class Program
{
...
intermediary.Import<DbSheets>();
...
}
This is the Resulting Error from trying to invoke the Import method
The type 'namespace.DbSheets' cannot be used as type parameter 'DbObj' in the generic type or method
'intermediary.Import<DbObj>()'
. There is no implicit reference conversion from 'namespace.DbSheets' to'namespace.BehaviorClass<IDomainObj>'
.
Summary of my thought process: In essence, I want a generic method to operate only on the classes derived from BehaviorClass, since I can reliably know they share a set of common methods and properties. Resharper says if I remove the generic constraint on the Import method, that the code will compile. I'd rather not remove that constraint, since this method specifically relies on the fact that this shared behavior will exist.
Note:
I'm using the IDomainObj
interface as a way to limit the generic parameter to a specific set of classes. It doesn't contain any specific functionality at this point.
It seems to me that you need two generic type parameters:
public void Import<TBehavior, TDomain>()
where TBehavior : BehaviorClass<TDomain>
where TDomain : IDomainObj
{
var instance = (TBehavior) Activator.CreateInstance(typeof(TBehavior), DbAccessor);
// STEP 1: Remove existing values
var existingValues = instance.Read();
instance.Delete(existingValues, out message);
// STEP 2: Create new IDomainObjects
var domainObjects = //LINQ Query.ToList();
// STEP 3: Add new IDomainObjects to the instance
instance.Create(domainObjects, message);
}
Now you should be able to call:
Import<DbSheets, Sheet>();
The problem before is that a DbSheets
isn't a BehaviorClass<IDomainObj>
- you can't call sheets.Create(new List<IDomainObj>())
for example.
It's slightly clunky having to specify two type arguments, and there are probably ways to avoid it, but this is the simplest approach to start with, I think.
See more on this question at Stackoverflow