C# C在未知泛型类型上调用方法
我有一个基类ManagerBase,它有一个通用的静态函数GetManager。有两个类继承自ManagerBase ManagerSomething1和ManagerSomething2。每个类都有一个静态函数GetManager,它返回继承的ManagerBase类型。我如何在不知道类型的情况下调用GetManagerC# C在未知泛型类型上调用方法,c#,generics,reflection,C#,Generics,Reflection,我有一个基类ManagerBase,它有一个通用的静态函数GetManager。有两个类继承自ManagerBase ManagerSomething1和ManagerSomething2。每个类都有一个静态函数GetManager,它返回继承的ManagerBase类型。我如何在不知道类型的情况下调用GetManager public class ManagerBase { public static T GetManager<T>(int managerID, bool
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, ...);
}
}
类似的方法可能会奏效:
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, ...});
您可以重构为如下内容:
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);
}
}
我认为您正试图在试图构建的类内部实现某种工厂模式 有两种方法可以实现:使用一个单独的类来知道如何构造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类。因此,需要回答的一个问题是如何做出决定。这是由数据读取器返回的某种数据决定的吗 与使用GetManager静态方法不同,您可以创建一个manager工厂或存储库类,该类了解如何在给定数据读取器的情况下确定要创建哪种类型的manager对象 下面是一个示例实现。其思想是,在早期的某个时刻,例如应用程序启动时,创建一个ManagerRepository,然后为您拥有的每种类型的管理器类注册一个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);
}
}
我不是很确定,但我有一种烦人的感觉,你正在尝试使用泛型,而基本多态性可以解决这个问题。你能解释一下决定你应该使用哪一种管理器的逻辑吗?没有真正的逻辑;SessionSharedHelper中定义的类型T与需要返回的类型相同。请告诉我该类型。如果OP坚持的话,你也可以让每个类都提供一个静态方法来给你del。我不确定这对我来说是如何工作的,因为InitializeSession函数只是用来检索管理器并将其粘贴到会话中。GetManager函数需要返回ManagerBase类型的对象。在InitializeSession中,T是从ManagerBase继承的对象。是的,它是一个ManagerBase。这就是我的想法,我开始在InitializeSession函数中编写if语句,编译器告诉我这两个条件都不能满足。在调试过程中,两个条件都不满足。很可能我遗漏了一些东西,这就是我在浏览器中而不是在VisualStudio中编写代码的原因。更正了cast与'as',异常的正确名称和括号数。您仍然应该考虑重构。这是一些严重的代码气味使用后期绑定从数据库填充对象?如果这不是一个玩具应用程序,我不推荐它。我同意,将此代码插入初始化会话不是最佳方法,我正在研究其他建议的解决方案。嗯。在重新阅读了这个问题之后,我意识到OP的情况需要一个比ManagerBase更具体的管理器类型,因此这可能不是解决这个特定问题的好方法。