Home > Enterprise >  How to use generic types in abstract class
How to use generic types in abstract class

Time:02-08

I'm trying to write a base class with some methods I want they are implemented in the classes that they inherit from this class.

In this example:

abstract public class ServiceBase 
{
    public ServiceBase()
    {
    }

    abstract public T Read<T>(string id);
    abstract public T Create<T>(T record);
    abstract public void Delete<T>(T record);
}

public class ServiceA: ServiceBase
{
    public Service(){}

    public override classA Read<classA>(string id)
    {
        ...
    }
    public override classA Create<classA>(classA record)
    {
        ...
    }
    public override void Delete<classA>(classA record)
    {
        ...
    }
}

public class ServiceB: ServiceBase
{
    public Service(){}

    public override classB Read<classB>(string id)
    {
        ...
    }
    public override classB Create<classB>(classB record)
    {
        ...
    }
    public override void Delete<classB>(classB record)
    {
        ...
    }
}

this show the next error: "no suitable method found to override"

Is it possible to make this correct? How?

CodePudding user response:

You need to declare the type T as part of your abstract class, and then pass a concrete type in your implementing class.

abstract public class ServiceBase<T> 
{
    public ServiceBase()
    {
    }

    abstract public T Read(string id);
    abstract public T Create<T>(T record);
    abstract public void Delete<T>(T record);
}

And then implementing, pass your type (in your example, either classA or classB) as such:

public class ServiceB: ServiceBase<classB>
{
    public Service(){}

    public override classB Read(string id)
    {
        ...
    }
    public override classB Create<classB>(classB record)
    {
        ...
    }
    public override void Delete<classB>(classB record)
    {
        ...
    }
}

CodePudding user response:

public class ClassA { }

public class ClassB { }

abstract public class ServiceBase<T> where T : class
{
    abstract public T Read(string id);
    abstract public T Create(T record);
    abstract public void Delete(T record);
}

public class ServiceConcrete1 : ServiceBase<ClassA> 
{
    public override ClassA Read(string id)
    {
        throw new NotImplementedException();
    }
    public override ClassA Create(ClassA record)
    {
        throw new NotImplementedException();
    }
    public override void Delete(ClassA record)
    {
        throw new NotImplementedException();
    }
}

public class ServiceConcrete2 : ServiceBase<ClassB>
{
    public override ClassB Read(string id)
    {
        throw new NotImplementedException();
    }
    public override ClassB Create(ClassB record)
    {
        throw new NotImplementedException();
    }
    public override void Delete(ClassB record)
    {
        throw new NotImplementedException();
    }
}

CodePudding user response:

This is similar to the accepted @jayGould answer, but with some additional tidbits to make it more inline with best practices.

I assume the target class for the service methods all have some commonality between them, and so it is useful to constrain ServiceBase<T> to use this common ancestor:

public interface IClass { }

public class ClassA  : IClass { }
public class ClassB  : IClass { }

abstract public class ServiceBase<T> where T:IClass
{
    protected ServiceBase() { }

    abstract public T Read(string id);
    abstract public T Create(T record);
    abstract public void Delete(T record);
}

public class ServiceA : ServiceBase<ClassA>
{
    public ServiceA() : base() { }

    public override ClassA Read(string id)
    {
        throw new NotImplementedException();
    }
    public override ClassA Create(ClassA record)
    {
        throw new NotImplementedException();
    }
    public override void Delete(ClassA record)
    {
        throw new NotImplementedException();
    }
}

public class ServiceB : ServiceBase<ClassB>
{
    public ServiceB() : base() { }

    public override ClassB Read(string id)
    {
        throw new NotImplementedException();
    }
    public override ClassB Create(ClassB record)
    {
        throw new NotImplementedException();
    }
    public override void Delete(ClassB record)
    {
        throw new NotImplementedException();
    }
}

Additionally, an abstract class should only have protected constructors since they can only be called from derived classes.

  •  Tags:  
  • Related