C#在未知泛型类型上调用方法

时间:2010-12-17 19:26:01

标签: c# generics reflection

我有一个基类“ManagerBase”,它有一个通用的静态函数“GetManager。有两个类继承自ManagerBase(”ManagerSomething1“和”ManagerSomething2“)。每个类都有一个静态函数”GetManager“,它返回继承类型的ManagerBase。如何在不知道类型的情况下调用GetManager?

public class ManagerBase
{
    public static T GetManager<T>(int managerID, bool withUsers, System.Func<SqlDataReader, T> del) where T : ManagerBase
    {
        T manager = del(dr);
        return manager;
    }
}

public class ManagerSomething1 : ManagerBase
{
    public static ManagerSomething1 GetManager<ManagerSomething1>(int managerID, bool withUsers)
    {
        return ManagerBase.GetManager<ManagerSomething1>(managerID, withUsers, dr => new ManagerSomething1(dr));
    }
}

public class ManagerSomething2 : ManagerBase
{
    public static ManagerSomething2 GetManager<ManagerSomething2>(int managerID, bool withUsers)
    {
        return ManagerBase.GetManager<ManagerSomething2>(managerID, withUsers, dr => new ManagerSomething2(dr));
    }
}

public static class SessionSharedHelper<T> where T : ManagerBase
{
    public static void InitializeSession(int managerID, bool withUsers)
    {
        SessionShared<T>.Manager = //I don't know how I can call ManagerBase.GetManager<T>(managerID, withUsers, ...);
    }
}

4 个答案:

答案 0 :(得分:3)

你可以重构这样的事情:

    public abstract class ManagerBase
    {
        public ManagerBase() { }

        public abstract void Initialize(int managerID, bool withUsers);
    }

    public class ManagerSomething1 : ManagerBase
    {
        public ManagerSomething1() 
        { }

        public override void Initialize(int managerID, bool withUsers)
        {
        }
    }

    public class ManagerSomething2 : ManagerBase
    {
        public ManagerSomething2()
        {
        }

        public override void Initialize(int managerID, bool withUsers)
        {
            throw new NotImplementedException();
        }
    }

    public static class SessionSharedHelper<T> where T : ManagerBase, new()
    {
        public static void InitializeSession(int managerID, bool withUsers)
        {
            T manager = new T();
            manager.Initialize(managerID, withUsers);
        }
    }

答案 1 :(得分:2)

这样的事可能有用:

MethodInfo method_info = typeof(T).GetMethod("GetManager",
   System.Reflection.BindingFlags.Static | BindingFlags.Public);
SessionShared<T>.Manager = 
   (T)method_info.Invoke(null, new object[]{managerID, withUsers, ...});

答案 2 :(得分:0)

我认为你正试图在你想要构建的类中实现某种工厂模式。

有两种方法可以实现:拥有一个知道如何构建Manager1和Manager2的单独类,或者让基类知道如何构造它的每个子节点。无论哪种方式,某些东西需要掌握每个子类的知识。我不认为有一个很好的方法来做你没有反思的东西。

我可能会在一个单独的工厂类中实现这样的东西。

public static T GetManager<T>(int managerID, bool withUsers) where T : ManagerBase
{
    if (typeof(T) == typeof(Manager1))
    {
        return new Manager1(managerID, withUsers) as T;
    }
    if (typeof(T) == typeof(Manager2))
    {
        return new Manager2(managerID, withUsers) as T;
    }

    throw new ArgumentException();
}

答案 3 :(得分:0)

当你说“给我managerID x的Manager *对象”时,某个地方必须知道/决定要创建哪种类型的Manager类。因此,需要回答的一个问题是如何做出决定。这是由数据读取器返回的某种数据决定的吗?

您可以创建一个管理器Factory或Repository类,而不是使用“GetManager”静态方法,该类了解如何在给定数据读取器的情况下确定要创建哪种类型的Manager对象。

以下是一个示例实现。这个想法是在早期的某个时刻,例如当您的应用程序启动时,您创建一个ManagerRepository,然后为您拥有的每种类型的Manager类注册一个“create”委托。稍后,当您从ManagerRepository请求Manager对象时,它将决定返回哪种类型的Manager类,并将使用您为该类型注册的“create”委托。

public class ManagerBase
{
}

class ManagerRepository
{
    private Dictionary<Type, Func<SqlDataReader, ManagerBase>> _ManagerCreateDelegates;

    public ManagerRepository()
    {
        _ManagerCreateDelegates = new Dictionary<Type, Func<SqlDataReader, ManagerBase>>();
    }

    public void RegisterCreate<T>(Func<SqlDataReader, ManagerBase> create)
        where T : ManagerBase
    {
        _ManagerCreateDelegates[typeof(T)] = create;
    }

    public ManagerBase GetManager(int managerID, bool withUsers)
    {
        SqlDataReader reader;
        reader = null;// TODO: obtain a data reader from somewhere...

        Type typeOfManager = this.DetermineManagerType(reader);

        Func<SqlDataReader, ManagerBase> create;
        if (_ManagerCreateDelegates.TryGetValue(typeOfManager, out create))
        {
            return create(reader);
        }
        else
        {
            throw new InvalidOperationException(string.Format("No create delegate has been registered for type [{0}].", typeOfManager.FullName));
        }
    }

    private Type DetermineManagerType(SqlDataReader reader)
    {
        // TODO: implement logic that uses the data reader to decide which type of Manager object to create
        throw new NotImplementedException();
    }
}

public class ManagerSomething1 : ManagerBase
{
    public ManagerSomething1(SqlDataReader reader)
    {
        // TODO: implement logic to construct ManagerSomething1 given a data reader
    }
}

public class ManagerSomething2 : ManagerBase
{
    public ManagerSomething2(SqlDataReader reader)
    {
        // TODO: implement logic to construct ManagerSomething1 given a data reader
    }
}

class Program
{
    static void Main(string[] args)
    {
        // create a ManagerRepository somewhere
        ManagerRepository repository = new ManagerRepository();

        // register create delegates for each type of Manager
        repository.RegisterCreate<ManagerSomething1>(dr => new ManagerSomething1(dr));
        repository.RegisterCreate<ManagerSomething2>(dr => new ManagerSomething2(dr));

        // use the repository
        int managerID = 5;
        bool withUsers = false;
        ManagerBase manager = repository.GetManager(managerID, withUsers);
    }
}