Приведение общего типа с использованием Activator.CreateInstance

у меня есть интерфейс

public interface ISomething<TValue>
    where TValue : IConvertible
{
    ...
}

Затем у меня также есть некоторый необщий класс с универсальным методом:

public class Provider
{
    public static void RegisterType<TValue>(ISomething<TValue> instance)
        where TValue : IConvertible
    {
        ...
    }
}

Кажется, все в порядке, пока я не захочу автоматически зарегистрировать все применимые типы в моей конкретной сборке.

public void InitializeApp()
{
    foreach(Type t in Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(ISomething<>).IsAssignableFrom(T)))
    {
        // ERROR
        Provider.RegisterType(Activator.CreateInstance(t));
    }
}

Этот код приводит к ошибке, поскольку тип аргумента нельзя вывести из использования. я должен либо

  1. предоставить явный универсальный тип с помощью моего универсального метода RegisterType (я не думаю, что смогу это сделать из-за динамического характера моего кода) или
  2. привести результаты из Activator.CreateInstance к соответствующему типу, чтобы тип аргумента можно было вывести из использования

Но я тоже не знаю, как быть? Может быть, есть третий вариант, о котором я не знаю.


person Robert Koritnik    schedule 03.06.2014    source источник
comment
Рассматривали ли вы вызов RegisterType через отражение и MakeGenericMethod? Либо так, либо вы, вероятно, должны иметь неуниверсальную ISomething и перегрузку RegisterType, которая использует это.   -  person Kirk Woll    schedule 03.06.2014


Ответы (1)


Универсальные типы — это функция времени компиляции, что означает, что универсальные типы должны быть известны во время компиляции. Таким образом, ваш метод RegisterType нельзя использовать, если вы знаете тип только во время выполнения, поскольку у компилятора нет возможности вывести общий параметр.

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

Для первого это будет выглядеть примерно так:

public void InitializeApp()
{
    foreach(Type t in Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(ISomething<>).IsAssignableFrom(T)))
    {
        var methodInfo = typeof( Provider ).GetMethod( "RegisterType", BindingFlags.Static );
        var registerTypeMethod = methodInfo.MakeGenericMethod( t );
        registerTypeMethod.Invoke( null, new[] { Activator.CreateInstance(t) } );
    }
}
person Kyle    schedule 03.06.2014
comment
Вы почти поняли это правильно, поэтому я принимаю ваш ответ как правильный, потому что он привел меня к решению. Для наследования универсального типа IsAssignableForm не поможет, если спросить об открытом универсальном типе, потому что он не может быть создан. Этот ответ помог в этом отношении. А также при вызове MakeGenericMethod мы должны предоставить аргумент универсального типа вместо самого типа, как вы это сделали. - person Robert Koritnik; 04.06.2014