静态构造函数注册对象构造函数=>未调用

时间:2019-03-17 08:14:15

标签: c# generics static-constructor

我想在派生类中使用静态构造函数来注册对象构造函数lambda,以便在传递某个Type对象时调用这些类。

由于仅在创建该类的第一个对象之前才调用静态构造函数,但是我想使用静态构造函数的结果来确定要创建哪种对象,因此该机制失败,未找到构造函数lambda

有什么办法吗?

public abstract class Cacheable
{
    // ... details do not matter ...
}

public class Series: Cacheable
{
    // ... details do not matter ...
}

public abstract class CacheableViewForm
{
    static Dictionary<Type, Func<CacheableViewForm>> cacheableViewFormConstructors = new Dictionary<Type, Func<CacheableViewForm>>();

    protected static void Register<CacheableViewFormClass, CacheableClass>()
        where CacheableViewFormClass: CacheableViewForm, new()
        where CacheableClass: Cacheable
    {
        cacheableViewFormConstructors[typeof(CacheableClass)] = (() => new CacheableViewFormClass());
    }

    public static CacheableViewForm CreateFromTargetType(Type cacheableType)
    {
        return cacheableViewFormConstructors[cacheableType]();
    }

    // ... details do not matter ...
}

public class SeriesViewForm: CacheableViewForm
{
    static SeriesViewForm() {Register<SeriesViewForm, Series>();}

    // ... details do not matter ...
}

// fails because CacheableViewForm.Register<> has not been executed yet!
CacheableViewForm newForm = CacheableViewForm.CreateFromTargetType(typeof(Series));

1 个答案:

答案 0 :(得分:0)

我的解决方案是将初始化(从派生类的静态构造函数)移至基类的静态构造函数(在执行对CreateFromTargetType方法的第一次调用之前自动调用该基类),并在其中使用反射在那里检查派生类。在派生类中,我定义了静态方法(TargetType),这些方法返回正在操作的特定Type

既不优雅也不紧凑,当然也不是超快的,但是它使我可以将派生类(例如SeriesViewForm)与其操作的数据类型(typeof(Series))之间的联系保持紧密(在相同的类定义中。

public abstract class CacheableViewForm: Form
{
    static Dictionary<Type, Func<CacheableViewForm>> CacheableViewFormConstructors = new Dictionary<Type, Func<CacheableViewForm>>();

    static CacheableViewForm()
    {
        var allAssemblies = AppDomain.CurrentDomain.GetAssemblies();

        foreach(Assembly assembly in allAssemblies)
        {
            Type[] cacheableViewFormTypes = assembly.GetExportedTypes().Where(t => typeof(CacheableViewForm).IsAssignableFrom(t) && t != typeof(CacheableViewForm)).ToArray();

            foreach (Type cacheableViewFormType in cacheableViewFormTypes)
            {
                MethodInfo mi = cacheableViewFormType.GetMethod("TargetType");
                Type cacheableType = (Type)mi.Invoke(null, null);
                Func<CacheableViewForm> ctorDelegate = (() => (CacheableViewForm)(Activator.CreateInstance(cacheableViewFormType)));
                CacheableViewFormConstructors[cacheableType] = ctorDelegate;
            }
        }
    }

    public static CacheableViewForm CreateFromTargetType(Type cacheableType)
    {
        return CacheableViewFormConstructors[cacheableType]();
    }
}

public class SeriesViewForm: CacheableViewForm
{
    public static Type TargetType() {return typeof(Series);}

    // ...
}