繁体   English   中英

C#调用未知通用类型的方法

[英]C# Calling a Method on an Unknown Generic Type

我有一个具有通用静态函数“ GetManager”的基类“ ManagerBase”。有两个继承自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, ...);
    }
}

您可以重构为以下内容:

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

这样的事情可能会起作用:

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

我认为您正在尝试在要构造的类中实现某种工厂模式。

您可以采用两种方法:有一个单独的类,该类知道如何构造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();
}

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM