Статический конструктор регистрирует объект constructor => не вызывается - PullRequest
0 голосов
/ 17 марта 2019

Я хотел использовать статический конструктор в производных классах для регистрации лямбда-выражений конструктора объекта для тех классов, которые будут вызываться при передаче определенного Type объекта.

Поскольку статический конструктор вызывается только перед первымобъект этого класса создан, но я хочу использовать результат статического конструктора, чтобы определить, какой тип объекта создать, этот механизм не работает, лямбда-конструктор не найден.

Есть ли выход из этого?

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 голосов
/ 17 марта 2019

Мое решение состоит в том, чтобы переместить инициализацию (из статического конструктора производных классов) в статический конструктор базового класса (который вызывается автоматически перед выполнением моего первого вызова метода 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);}

    // ...
}
...