callisto
callisto

Reputation: 5083

Getting correct subclass method from generic superclass definition

How I implement a generic method defined in a superclass in multiple subclasses? I need the correct subclass method to be decided by the type of the calling subclass instance:

var someClassObj = new SubClass();
var = someClassObj.BuildList(v1, v2);

public abstract class SomeBase
{
    public List<T> BuildList<T>(int v1, int v2)
    {
        var results = new List<T>();

        for (int i = v1; i < v2; i++)
        {
            results.Add(AddItem<T>());
        }
        return results;
    }

    protected abstract T AddItem<T>();
}

public class SubClass : SomeBase
{


    protected override BusinessThing AddItem<T>()
    {
        var entity = new BusinessThing();
        entity.Name1 = "1";
        entity.Name2 = "2";
        entity.Name3 = "3";
        return entity;
    }
}

public class BusinessThing
{
    public string Name1 { get; set; }
    public string Name2 { get; set; }
    public string Name3 { get; set; }
}

The above does not build: Cannot change return type when overriding method 'T SomeBase.AddItem()'

Upvotes: 1

Views: 267

Answers (2)

helb
helb

Reputation: 7773

If you don't want to have generic classes as Daniel suggests, you can also tell the compiler what T is using the where clause to restrict the generic type:

public abstract class SomeBase
{
    public List<T> BuildList<T>(int v1, int v2) where T: BusinessThing
    {
        var results = new List<T>();

        for (int i = v1; i < v2; i++)
        {
            results.Add(AddItem<T>());
        }
        return results;
    }

    protected abstract T AddItem<T>() where T:BusinessThing;
}

public class SubClass : SomeBase
{
    protected override T AddItem<T>()
    {
        var entity = new BusinessThing();
        entity.Name1 = "1";
        entity.Name2 = "2";
        entity.Name3 = "3";
        return (T)entity;
    }
}

Then use it as follows:

var someClassObj = new SubClass();
var list = someClassObj.BuildList<BusinessThing>(5, 7);

This also allows you to use a derived ConcreteBusinessThing class which derives from BusinessThing which should also work using:

public class SubClass : SomeBase
{
    protected override T AddItem<T>()
    {
        var entity = new ConcreteBusinessThing();
        entity.Name1 = "1";
        entity.Name2 = "2";
        entity.Name3 = "3";
        return (T)(object)entity; // ugly cast but is always ok
    }
}

and calling it with:

var someClassObj = new SubClass();
var list = someClassObj.BuildList<ConcreteBusinessThing>(5, 7);

Upvotes: 1

Daniel Hilgarth
Daniel Hilgarth

Reputation: 174329

You would make your base class generic instead of its methods:

public abstract class SomeBase<T>
{
    public List<T> BuildList(int v1, int v2)
    {
        var results = new List<T>();

        for (int i = v1; i < v2; i++)
        {
            results.Add(AddItem());
        }
        return results;
    }

    protected abstract T AddItem();
}

public class SubClass : SomeBase<BusinessThing>
{
    protected override BusinessThing AddItem()
    {
        var entity = new BusinessThing();
        entity.Name1 = "1";
        entity.Name2 = "2";
        entity.Name3 = "3";
        return entity;
    }
}

Upvotes: 3

Related Questions