Compiler gives implicit conversion error || My generic method's constraint is an abstract generic class

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.

Jon Skeet
people
quotationmark

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.

people

See more on this question at Stackoverflow