lundi 16 novembre 2020

C# - Get FieldInfo value from static readonly members of static classes using reflection

I'm trying to make a system that using reflection and during compilation time, it's able to generate a configuration file for some classes. The usage of a configuration file is to avoid using reflection at runtime. Let me explain.

I have something like

public abstract class BaseClass
{
    public abstract string ID { get; }
}

and multiple implementations like

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"; } }
}

What I did in order to be able to use each implementations in their proper context in a static way, is to create for each context a static class like this:

namespace ContextOne
{
    internal static class Container
    {
        public static readonly ClassOne = new ClassOne();
    }
}

In this way, sharing the BaseClass with all the contexts, I can create multiple children that defines specific values for specific usages. In a context, i can define a .cs file like this:

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();
    }
}

I also made a static class in which the static constructor is using reflection to get all the members defined in all the Assemblies of the project so that it can keep an updated internal cache of all these classes associating to them a configuration that is saved on a text file. The cache is a dictionary in which I use the ID defined in each class as key and a ConfigClass as value. I disabled the execution of all the code that uses reflection at runtime. This is a very simplified version of this class:

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;
    }
}

as you can see from the code, I'm not able to get the ID from the FieldInfo object I got with reflection. I tried using

string id = field.GetValue(null) as string;

but I'm obviously making a mistake: I probably need to get the static instance of the derived classes defined in the Container in order to do that, but I have no clue on how to do it. Possibly, once the instance is defined, it should stick to the static member so that I will not create other instances causing memory leaks or other sort of issues.

Thank you very much !! :)





Aucun commentaire:

Enregistrer un commentaire