如何访问外部程序集内部类EntityNetPlayer的List私有字段及创建该类List字段?
这两个问题其实都绕不开.NET中internal类型的访问限制,我来一步步给你拆解解决办法:
问题1:泛型参数T为内部类时,如何访问List?
你已经通过反射拿到了List<T>的实例(就是GetAlivePlayers方法返回的对象),但因为T是外部程序集的internal类,没法直接在代码里写List<EntityNetPlayer>强转,这里有两种实用方案:
方案1:用dynamic简化操作
把获取到的对象转成dynamic类型,就能直接调用List的方法、遍历元素,甚至访问内部类的属性/字段(前提是你知道它们的名称):object alivePlayersObj = GetAlivePlayers(yourInstance); dynamic alivePlayers = alivePlayersObj; // 遍历所有玩家 foreach (dynamic player in alivePlayers) { // 假设EntityNetPlayer有IsAlive属性,直接访问 bool isPlayerAlive = player.IsAlive; // 也可以结合反射操作内部字段 object internalFieldValue = player.GetType() .GetField("SomeInternalField", BindingFlags.Instance | BindingFlags.NonPublic) .GetValue(player); }这种方式代码简洁,但没有编译时校验,拼写错误只会在运行时暴露。
方案2:全程用反射操作List
如果你不想依赖dynamic,完全可以用反射调用List的属性和方法:object alivePlayersObj = GetAlivePlayers(yourInstance); Type listType = alivePlayersObj.GetType(); // 获取List的元素数量 int playerCount = (int)listType.GetProperty("Count").GetValue(alivePlayersObj); // 通过索引器遍历所有元素 PropertyInfo indexerProp = listType.GetProperty("Item", new[] { typeof(int) }); for (int i = 0; i < playerCount; i++) { object player = indexerProp.GetValue(alivePlayersObj, new object[] { i }); // 对player进行反射操作,比如获取公开属性 string playerName = (string)player.GetType().GetProperty("PlayerName").GetValue(player); }
问题2:如何创建外部程序集internal类(EntityNetPlayer)的List字段?
要创建List<EntityNetPlayer>类型的实例,核心是先拿到EntityNetPlayer的Type,再动态构建泛型List类型:
获取EntityNetPlayer的Type
因为这个类和你传入GetAlivePlayers的instance对象属于同一个外部程序集,你可以从实例的程序集里获取它的Type(注意要写全类的命名空间):// 从instance所在程序集获取EntityNetPlayer的Type Type entityNetPlayerType = instance.GetType().Assembly.GetType("YourFullNamespace.EntityNetPlayer");如果你知道外部程序集的名称,也可以直接加载程序集获取:
Assembly externalAssembly = Assembly.Load("ExternalAssemblyName"); Type entityNetPlayerType = externalAssembly.GetType("YourFullNamespace.EntityNetPlayer");构建并实例化List
拿到Type后,用typeof(List<>)结合MakeGenericType创建泛型List类型,再通过Activator.CreateInstance实例化:// 创建List<EntityNetPlayer>的类型 Type listType = typeof(List<>).MakeGenericType(entityNetPlayerType); // 实例化一个空的List object newAlivePlayersList = Activator.CreateInstance(listType);(可选)给原字段赋值
如果要替换原来的AlivePlayers字段,直接用反射的SetValue方法:instance.GetType() .GetField("AlivePlayers", BindingFlags.Instance | BindingFlags.NonPublic) .SetValue(instance, newAlivePlayersList);
小提示
如果外部程序集没有给你的程序集添加InternalsVisibleToAttribute,你永远没法在代码里直接引用EntityNetPlayer类型,只能全程靠反射或dynamic间接操作——这是.NET访问权限机制的硬性限制。
内容的提问来源于stack exchange,提问作者Szymon Grzech

