user924069
user924069

Reputation:

C# Generic Method T Class T Override

In C# I have a generic class that looks like this:

public class DataManager<T> : IDisposable where T : class

That is used like this:

    public T GetById(String id)
    {
        return this.Context.Set<T>().Find(id);
    }

This works great.

However if I have 2 types in a manager, in this case, Ticket and TicketResponse, I would like to be able to override the type without having to add the type into every method call. Something like this:

    public T GetById<T>(String id) where T : class
    {
        return this.Context.Set<T>().Find(id);
    }

Where I can call it interchangeably like so:

    var ticket = GetById(myId);
    var ticketResponse = GetById<TicketResponse>(myId); // this would override

The idea is to not have to create a separate manager for a sub-object, but also to not have to get the entire ticket to have to iterate through the responses, but just be able to get it directly.

Is this possible?

Upvotes: 0

Views: 416

Answers (4)

Heinzi
Heinzi

Reputation: 172330

You could use a wrapper that encapsulates two DataManagers:

class DataAndResponseManager<TData, TResponse>
{
    private dataManager = new DataManager<TData>();
    private responseManager = new DataManager<TResponse>();

    public TData GetById(String id) { dataManager.GetById(id); }
    public TResponse GetResponseById(String id) { responseManager.GetById(id); }
}

Advantage: Reuse of all existing DataManager code.

Disadvantage: Proxy methods required.

Upvotes: 0

Kyle
Kyle

Reputation: 6684

You could try something like this:

public T GetById( String id )
{
    return GetById<T>( id );
}

public U GetById<U>( String id ) where U : T
{
    return this.Context.Set<U>().Find( id );
}

So you have your original method but also an additional generic method which can take another parameter type that derives from T.

Upvotes: 1

Lee
Lee

Reputation: 144136

Since the Context.Set allows you to specify any T you want, you could add an interface for the DataManager class, add a base class which exposes a method on the underlying context and then implement the interface explicitly on your manager class:

public interface IDataManager<T> : IDisposable where T : class
{
    T GetById(string id);
}

public class DataManagerBase : IDisposable
{
    protected Find<T>(string id) where T : class
    {
        return this.Context.Set<T>().Find(id);
    }
}

public class TicketManager : DataManagerBase, IDataManager<TicketResponse>, IDataManager<Ticket>
{
    TicketResponse IDataManager<TicketResponse>.GetById(string id)
    {
        return this.Find<TicketResponse>(id);
    }

    Ticket IDataManager<Ticket>.GetById(string id)
    {
        return this.Find<TicketResponse>(id);
    }
}

Upvotes: 2

Heinzi
Heinzi

Reputation: 172330

If I understood you correctly, Ticket is a special case: Ticket's DataManager should also provide methods for TicketResponse. Is that correct?

In that case, you can just subclass DataManager<T> and add the required functionality:

class TicketManager : DataManager<Ticket>
{
    public TicketResponse GetResponseById(String id)
    {
        return this.Context.Set<TicketResponse>().Find(id);
    }
}

which can be used as follows:

var ticket = myTicketManager.GetById(myId);
var ticketResponse = myTicketManager.GetResponseById(myId);

(If you are worried about the duplication of the GetById code, just extract it into a static protected GetByIdInternal<TData> method.)

Upvotes: 0

Related Questions