Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#-使用反射从静态类的静态只读成员获取FieldInfo值_C#_Reflection - Fatal编程技术网

C#-使用反射从静态类的静态只读成员获取FieldInfo值

C#-使用反射从静态类的静态只读成员获取FieldInfo值,c#,reflection,C#,Reflection,我正在尝试制作一个系统,使用反射,在编译期间,它能够为一些类生成一个配置文件。 配置文件的使用是为了避免在运行时使用反射。 让我解释一下 我有点像 public abstract class BaseClass { public abstract string ID { get; } } 以及多种实现,如 public class ClassOne : BaseClass { public override string ID { get { return "Clas

我正在尝试制作一个系统,使用反射,在编译期间,它能够为一些类生成一个配置文件。 配置文件的使用是为了避免在运行时使用反射。 让我解释一下

我有点像

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();
    }
}
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();
    }
}
这样,通过与所有上下文共享基类,我可以创建多个子类,为特定用法定义特定值。在上下文中,我可以这样定义.cs文件:

namespace ContextOne
{
    internal static class Container
    {
        public static readonly ClassOne = new ClassOne();
    }
}
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;
    }
}
但我显然犯了一个错误:我可能需要获取容器中定义的派生类的静态实例才能做到这一点,但我不知道如何做到这一点。很可能,一旦定义了实例,它就应该保留静态成员,这样我就不会创建导致内存泄漏或其他问题的其他实例


非常感谢!!:)

据我所知,该类的ID是固定的,ClassOne类的所有实例都共享相同的ID,因此实际上ID不应该是该类的属性,而是一些元信息

如果是这样,您应该创建IDAttribute并用它标记您的类。
您仍然可以在BaseClass中使用ID属性,它将从属性中获取ID。

据我所知,该类的ID是固定的,ClassOne的所有实例都共享相同的ID,因此实际上ID不应该是该类的属性,而是一些元信息

如果是这样,您应该创建IDAttribute并用它标记您的类。
您仍然可以在BaseClass中使用ID属性,它将从属性中获取ID。

您已经完成了所有艰苦的工作,归根结底,所有这些都是需要从静态容器中获取类的实例,然后读取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);
 }
我对您的代码进行了简化,以向您展示:

本例中的
字段
实际上是类的实例,而不是ID属性,这就是代码无法工作的原因


如果您只创建了
ID
属性来重复类名,那么您可以只执行
field.FieldType.name
,而不需要实际获取实例。

您已经完成了所有的艰苦工作,所有这些归结起来就是需要从静态容器中获取类的实例,然后读取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);
 }
我对您的代码进行了简化,以向您展示:

本例中的
字段
实际上是类的实例,而不是ID属性,这就是代码无法工作的原因


如果您只创建了
ID
属性来重复类名,那么您可以只执行
field.FieldType.name
,而不需要实际获取实例。

感谢您的回答:它成功了!!:)一开始,我实际上使用ID作为Type.Name,但这并不实际,因为我在内部使用ID:它不仅仅用于字典。无论如何,再次非常感谢。谢谢你的回答:成功了!!:)一开始,我实际上使用ID作为Type.Name,但这并不实际,因为我在内部使用ID:它不仅仅用于字典。无论如何,再次非常感谢。你好,谢谢你的回答。您的方法确实很有趣,尽管它不适用于我的案例,但有两个原因:(1)此机制将包含在库中,因此,我需要强制定义基类实例的人员定义ID。您可以强制定义派生类中的属性吗?(2) ID是在运行时内部使用的,它不仅仅用于字典,因此,使用该属性意味着我仍然必须在运行时缓存它。看到所有这些都是为了避免反思,这将是毫无意义的。您好,谢谢您的回答。您的方法确实很有趣,尽管它不适用于我的案例,但有两个原因:(1)此机制将包含在库中,因此,我需要强制定义基类实例的人员定义ID。您可以强制定义派生类中的属性吗?(2) ID是在运行时内部使用的,它不仅仅用于字典,因此,使用该属性意味着我仍然必须在运行时缓存它。看到所有这些都是为了避免反射,这将是毫无意义的。