简体   繁体   中英

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?

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);
    }
}

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 .

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.)

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.

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