如何向UserManager传递自定义类类型并创建其实例?
解决自定义命令类的实例化与关联问题
嘿,你已经摸到了核心方向,只是在泛型实例化和类型传递这步有点卡壳——我来帮你把思路理顺,给出可运行的方案!
首先修正UserManager的泛型实现
你之前的泛型尝试思路是对的,但有几个关键问题:
- 泛型参数需要类型约束,确保传入的T必须是
UserClass的子类,并且能被实例化 - 不能直接在非泛型类级别声明
List<T>,可以用基类UserClass统一存储实例,或者把UserManager本身做成泛型类
方案1:把UserManager做成泛型类(适合单一命令类场景)
这种方式最直接,强制UserManager只处理一种自定义命令类:
public class UserInfo { public int id; public UserInfo(int _id) => id = _id; } // 基类保持不变 public class UserClass { public UserInfo userInfo; } // 泛型UserManager,约束T必须是UserClass子类且有无参构造 public class UserManager<T> where T : UserClass, new() { private List<UserInfo> _userInfos; public List<T> ChildInstances { get; private set; } = new List<T>(); public UserManager(List<UserInfo> userInfos) { _userInfos = userInfos; SetupChildInstances(); } private void SetupChildInstances() { foreach (var userInfo in _userInfos) { // 创建子类实例并关联UserInfo T child = new T(); child.userInfo = userInfo; ChildInstances.Add(child); } } }
方案2:非泛型UserManager支持多类型(适合多命令类场景)
如果你的库需要支持用户创建多种自定义命令类,可以用List<UserClass>存储,通过泛型方法动态创建:
public class UserManager { private List<UserInfo> _userInfos; public List<UserClass> AllChildInstances { get; private set; } = new List<UserClass>(); public UserManager(List<UserInfo> userInfos) { _userInfos = userInfos; } // 泛型方法,创建指定类型的子类实例并关联UserInfo(无参构造) public void RegisterChildClass<T>() where T : UserClass, new() { foreach (var userInfo in _userInfos) { T child = new T(); child.userInfo = userInfo; AllChildInstances.Add(child); } } // 支持带参数构造函数的版本 public void RegisterChildClassWithConstructor<T>(params object[] extraArgs) where T : UserClass { foreach (var userInfo in _userInfos) { // 把userInfo作为第一个构造参数,后续传入用户自定义参数 T child = (T)Activator.CreateInstance(typeof(T), userInfo, extraArgs); AllChildInstances.Add(child); } } }
然后实现[Command]属性的自动调用逻辑
你提到了[Command]属性,这需要用反射来扫描方法并存储,当收到命令时自动触发:
首先定义Command属性:
[AttributeUsage(AttributeTargets.Method)] public class CommandAttribute : Attribute { // 可选:允许用户自定义命令名称 public string CommandName { get; } public CommandAttribute(string commandName = null) => CommandName = commandName; }
然后在UserManager里添加命令扫描和调用的逻辑(以非泛型版本为例):
public class UserManager { // 存储命令映射:命令名称 -> (实例, 方法) private Dictionary<string, (UserClass Instance, MethodInfo Method)> _commandMap = new Dictionary<string, (UserClass, MethodInfo)>(); public void RegisterChildClass<T>() where T : UserClass, new() { foreach (var userInfo in _userInfos) { T child = new T(); child.userInfo = userInfo; AllChildInstances.Add(child); // 扫描当前实例的Command方法 ScanForCommands(child); } } private void ScanForCommands(UserClass instance) { var methods = instance.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance) .Where(m => m.GetCustomAttribute<CommandAttribute>() != null); foreach (var method in methods) { var attr = method.GetCustomAttribute<CommandAttribute>(); // 优先用用户自定义的命令名,否则用方法名 string commandName = attr.CommandName ?? method.Name.ToLower(); _commandMap[commandName] = (instance, method); } } // 调用命令的方法(从Socket收到命令后触发) public bool ExecuteCommand(string commandName, int userId, params object[] args) { // 根据userId找到对应用户的命令实例 var targetInstance = AllChildInstances.FirstOrDefault(c => c.userInfo.id == userId); if (targetInstance == null) return false; if (_commandMap.TryGetValue(commandName.ToLower(), out var commandData) && commandData.Instance == targetInstance) { try { commandData.Method.Invoke(targetInstance, args); return true; } catch (Exception ex) { // 处理调用错误(比如参数不匹配) Console.WriteLine($"Command execution failed: {ex.Message}"); return false; } } return false; } }
用户侧的代码调整(以非泛型UserManager为例)
用户的自定义类和管理器可以这样写:
public class ChildClass : UserClass { private CustomManager _customManager; // 带参数的构造函数,接收UserInfo和CustomManager public ChildClass(UserInfo userInfo, CustomManager customManager) { this.userInfo = userInfo; _customManager = customManager; } [Command] // 用方法名作为命令名 public void Message(string _message) { _customManager.ReceiveMessage(userInfo.id, _message); } } public class CustomManager { private UserManager _userManager; public CustomManager(List<UserInfo> userInfos) { _userManager = new UserManager(userInfos); // 注册自定义类,传入当前CustomManager作为构造参数 _userManager.RegisterChildClassWithConstructor<ChildClass>(this); } public void ReceiveMessage(int _id, string _message) { Console.WriteLine($"We got message: {_message} from user with id: {_id}"); } }
额外优化建议
- 缓存反射结果:如果服务器性能要求高,可以在程序启动时缓存所有带
[Command]属性的方法,避免每次实例化都扫描 - 依赖注入:可以引入简单的DI容器来管理CustomManager等依赖,避免手动传递构造参数
- 命令参数校验:在ExecuteCommand里添加参数类型匹配的校验,避免调用出错
- 抽象基类增强:如果需要强制子类必须实现某些逻辑,可以把UserClass改成抽象类,定义抽象方法
内容的提问来源于stack exchange,提问作者Bizio
相关产品推荐
相关产品推荐

