c# - C# - 使用反射从静态类的静态只读成员中获取 FieldInfo 值
问题描述
我正在尝试制作一个使用反射的系统,并且在编译期间,它能够为某些类生成配置文件。配置文件的使用是为了避免在运行时使用反射。让我解释。
我有类似的东西
public abstract class BaseClass
{
public abstract string ID { get; }
}
以及多种实现方式,例如
public class ClassOne : BaseClass
{
public override string ID { get { return "Class1"; } }
}
public class ClassTwo : BaseClass
{
public override string ID { get { return "Class2"; } }
}
public class ClassThree : BaseClass
{
public override string ID { get { return "Class3"; } }
}
为了能够以静态方式在适当的上下文中使用每个实现,我所做的是为每个上下文创建一个像这样的静态类:
namespace ContextOne
{
internal static class Container
{
public static readonly ClassOne = new ClassOne();
}
}
通过这种方式,与所有上下文共享 BaseClass,我可以创建多个为特定用途定义特定值的子级。在上下文中,我可以像这样定义一个 .cs 文件:
namespace MyContext
{
public class MyClass : BaseClass
{
public override string ID { get { return "MyClass"; } }
}
public class YourClass : BaseClass
{
public override string ID { get { return "YourClass"; } }
}
internal static class Container
{
public static readonly MyClass Option1 = new MyClass();
public static readonly YourClass Option2 = new YourClass();
}
}
我还创建了一个静态类,其中静态构造函数使用反射来获取在项目的所有程序集中定义的所有成员,以便它可以保持所有这些类的更新内部缓存与它们相关联的配置保存在文本文件。缓存是一个字典,其中我使用每个类中定义的 ID 作为键,使用 ConfigClass 作为值。我禁用了在运行时使用反射的所有代码的执行。这是这个类的一个非常简化的版本:
public static class Manager
{
private static readonly Dictionary<string, ConfigClass> _cache = new Dictionary<string, ConfigClass>();
static Manager()
{
_cache = LoadFile();
// get a collection of valid IDs defined in the project.
List<string> validIDs = new List<string>();
List<Type> containers = GetTypesWithNameInAllAssemblies(".Container", true);
foreach(var cont in containers)
{
MemberInfo[] members = cont.GetMembers(BindingFlag.Static | BindingFlag.Public);
foreach(var mb in members)
{
FieldInfo field = cont.GetField(mb.Name);
if(field.FieldType.BaseType == typeof(BaseType)
{
//*********************
string id = /* TODO */;
//*********************
validIDs.Add(id);
}
}
}
// update the cache.
AddMissingEntriesToCache(validIDs, _cache);
RemoveObsoleteEntriesFromCache(validIDs, _cache);
SaveFile(_cache);
}
private static List<Type> GetTypesWithNameInAllAssemblies(string name, bool fullNameEndsWith = false)
{
List<Type> wantedTypes = new List<Type>();
Assembly[] assemblies = GetAssemblies();
for (int i = 0; i < assemblies.Length; i++)
{
Type[] types = assemblies[i].GetTypes();
for (int j = 0; j < types.Length; j++)
{
if (fullNameEndsWith)
{
if (types[j].FullName.EndsWith(name))
{
wantedTypes.Add(types[j]);
}
}
else
{
if (types[j].Name == name)
{
wantedTypes.Add(types[j]);
}
}
}
}
return wantedTypes;
}
}
正如您从代码中看到的那样,我无法从通过反射获得的 FieldInfo 对象中获取 ID。我尝试使用
string id = field.GetValue(null) as string;
但我显然犯了一个错误:我可能需要获取容器中定义的派生类的静态实例才能做到这一点,但我不知道如何去做。可能,一旦定义了实例,它应该坚持静态成员,这样我就不会创建其他导致内存泄漏或其他类型问题的实例。
非常感谢 !!:)
解决方案
你已经完成了所有艰苦的工作,这一切归结为需要从你的静态容器中获取类的实例,然后读取 ID:
if(field.FieldType.BaseType == typeof(BaseClass))
{
var instance = (BaseClass)field.GetValue(null); // null as this is a static field
//*********************
string id = instance.ID;
//*********************
validIDs.Add(id);
}
我已经为您制作了一个精简的代码示例来向您展示:https ://dotnetfiddle.net/rEjJHw
在field
这种情况下,实际上是类的实例,而不是 ID 属性,这就是您的代码不起作用的原因。
如果您只创建该ID
属性来重复类名,那么您可能已经完成field.FieldType.Name
并且根本不需要实际获取实例。
推荐阅读
- haskell - 如何在 Haskell 中对函数进行柯里化
- javascript - 将不同网站的内容设置为 JS 变量
- tensorflow - 简单模型无法在 tpu 上运行(在 colab 上)
- php - 上传文件并以原始名称保存在存储文件夹中
- node.js - 收到客户端响应后如何停止计时器运行?
- javascript - 通过 SPA Web 应用程序的屏幕截图生成报告 - 设计选择和选项
- swift - Swift 短路与逻辑运算符未按预期工作
- php - 在 MySQL 中通过在 JSON 列上执行连接从两个表中获取数据时遇到问题
- android - ImageView 源始终覆盖其背景 Android
- python - Pandas:给定特定信号值的前进和后退行数