简体   繁体   中英

Take class which implements interface

I have an abstract base model class which contains some shared properties. On top of that I have a number of minor interfaces, which defines what processes a model will be available for.

Here is an example of the base class, an interface and a derived class:

public abstract class ModelBase
{
    public ModelBase(string name) 
    {
        Name = name;
    }

    public int Id { get; private set; }

    public int Name { get; private set; }
}


public interface ISupportProcessA
{
    public decimal Amount { get; }
}


public class ModelDerived : ModelBase
{
    public ModelDerived(string name) : base(name) { }

    public decimal Amount { get; private set; }
}

To perform some work with the base model I also have an abstract base processor class, with some shared functionaliy and some derived processor classes, one for each process. It could look like this:

public abstract class ProcessorBase
{
    private readonly ModelBase model;

    public ProcessorBase(ModelBase model)
    {
        this.model = model;
    }

    // ...some shared methods
 }


 public class ProcessorA : ProcessorBase 
 {
     private readonly ISupportProcessA model;

     public ProcessorA(ISupportProcessA model) : base(model)
     {
         this.model = model;
     }

     // ...some specific methods
 }

Now here lies the problem. Because ISupportProcessA is not (to the compilers knowledge) related to ModelBase and can therefore not be given as input in base() . That makes sense.

So what I tried to do was to create an interface IModelBase which I use instead of ModelBase . However, this gives some issues once I connect to Entity Framework, which doesn't work well with interfaces (or maybe it's just me?).

So here is my question:

Is there anyway to request a class which both derives from ModelBase but also implements ISupportProcessA ?

You can get some of the way there with generics:

public class ProcessorA<TModel> : ProcessorBase where TModel : ModelBase, ISupportProcessA
{
    private readonly ISupportProcessA model;

    public ProcessorA(TModel model) : base(model)
    {
        this.model = model;
    }

    // ...some specific methods
}

This is a bit ugly however, as you need to create a new ProcessorA<ModelDerived> , rather than just a ProcessorA .


You can add more boilerplate to make things a bit nicer:

public abstract class ProcessorBase
{
    protected abstract ModelBase ModelForBase { get; }


    // ...some shared methods
}

public abstract class ProcessorA : ProcessorBase
{
    public static ProcessorA Create<TModel>(TModel model) where TModel : ModelBase, ISupportProcessA
    {
        return new ProcessorA<TModel>(model);
    }

    // Abstract specific methods
    public abstract void SomeSpecificMethod();
}


public class ProcessorA<TModel> : ProcessorA where TModel : ModelBase, ISupportProcessA
{
    protected override ModelBase ModelForBase => model;

    private readonly TModel model;

    public ProcessorA(TModel model)
    {
        this.model = model;
    }

    // Specific method overrides
    public override void SomeSpecificMethod()
    {
    }
}

This means you can do ProcessorA processor = ProcessorA.Create(new Model()) , but at the cost of a lot more boilerplate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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