Рефлексия отражения - PullRequest
0 голосов
/ 28 мая 2010

В настоящее время я пытаюсь создать универсальную фабрику экземпляров, для которой в качестве универсального параметра используется интерфейс (применяется в конструкторе), а затем позволяет получить экземпляры объектов, реализующие этот интерфейс, из всех типов во всех загруженных сборках.

Текущая реализация выглядит следующим образом:

public class InstantiationFactory<T>
{
    protected Type Type { get; set; }

    public InstantiationFactory()
    {
        this.Type = typeof(T);
        if (!this.Type.IsInterface)
        {
            // is there a more descriptive exception to throw?
            throw new ArgumentException(/* Crafty message */);
        }
    }

    public IEnumerable<Type> GetLoadedTypes()
    {
        // this line of code found in other stack overflow questions
        var types = AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany(a => a.GetTypes())
            .Where(/* lambda to identify instantiable types which implement this interface */);

        return types;
    }

    public IEnumerable<T> GetImplementations(IEnumerable<Type> types)
    {
        var implementations = types.Where(/* lambda to identify instantiable types which implement this interface */
            .Select(x => CreateInstance(x));

        return implementations;
    }

    public IEnumerable<T> GetLoadedImplementations()
    {
        var loadedTypes = GetLoadedTypes();
        var implementations = GetImplementations(loadedTypes);
        return implementations;
    }

    private T CreateInstance(Type type)
    {
        T instance = default(T);

        var constructor = type.GetConstructor(Type.EmptyTypes);
        if (/* valid to instantiate test */)
        {
            object constructed = constructor.Invoke(null);
            instance = (T)constructed;
        }

        return instance;
    }
}

Мне кажется полезным, чтобы моя функция CreateInstance(Type) была реализована как метод расширения, чтобы я мог использовать ее позже и упростить код моей фабрики, но я не могу понять, как вернуть строго типизированное значение из этого метод расширения.

Я понимаю, что могу просто вернуть объект:

public static class TypeExtensions
{
    public object CreateInstance(this Type type)
    {
        var constructor = type.GetConstructor(Type.EmptyTypes);
        return /* valid to instantiate test */ ? constructor.Invoke(null) : null;
    }
}

Возможно ли, чтобы метод расширения создавал подпись для каждого экземпляра типа, который он расширяет?

Мой идеальный код был бы таким, чтобы избежать необходимости приводить результат вызова к CreateInstance():

Type type = typeof(MyParameterlessConstructorImplementingType);
MyParameterlessConstructorImplementingType usable = type.CreateInstance();

Ответы [ 3 ]

2 голосов
/ 28 мая 2010

Я не думаю, что это возможно, потому что вы пытаетесь получить время компиляции информацию о типах (строго типизация) типов, которые вы знаете только в время выполнения . Вам придется работать с вашими интерфейсами.

Проблема в том, что вы не знаете, какие типы будут содержаться в ваших сборках во время компиляции. Вы даже можете использовать переменную для имени вашей сборки! Ваша сборка может содержать любую реализацию вашего интерфейса. Таким образом, нет никакой возможности указать компилятору создать строго типизированный экземпляр типа, который вы загружаете из вашей сборки.

0 голосов
/ 20 октября 2015

Почему бы не попробовать использовать дженерики в вашем методе Extension с ограничениями?

public static class TypeExtensions
{
    public T CreateInstance<T>(this T type) where T : Type
    {
        var constructor = type.GetConstructor(Type.EmptyTypes);
        return /* valid to instantiate test */ ? constructor.Invoke(null) : null;
    }
}
0 голосов
/ 28 мая 2010

Может как то так? Я не вижу способа без приведения или общего параметра типа для обработки приведения внутри. Я использую нечто похожее на это, когда у меня есть объект Type подкласса, но я использую только методы базового класса и т. Д. В вызывающей стороне.

public static object New( this Type type )
{
    return type.GetConstructor( Type.EmptyTypes ).Invoke( null );
}

public static T New<T>( this Type type )
{
    return (T)type.GetConstructor( Type.EmptyTypes ).Invoke( null );
}

// usage
MyParameterless usable = (MyParameterless)type.New();
MyParameterless usable 2 = type.New<MyParameterless>();
...