Unity ResolveAll Универсальный интерфейс

Я использую Unity IoC, я хотел бы зарегистрировать отображение не универсального класса в универсальный интерфейс. После этого я хотел бы использовать метод ResolveAll для получения всей регистрации, связанной с универсальным интерфейсом. Это пример кода:

interface ISample<out T> { }
class Ca : ISample<int> { }
class Cb : ISample<string> { }

class Program
{
    static void Main(string[] args)
    {

        var container = new UnityContainer();
        container.RegisterType<ISample<int>,Ca>();
        container.RegisterType<ISample<string>, Cb>();

        var classList = container.ResolveAll(typeof(ISample<>));
    }
}

в моем коде эта строка:

var classList = container.ResolveAll(typeof(ISample<>));

это ошибка:

Resolution of the dependency failed, type = "ConsoleApplication1Unity.ISample`1[T][]", name = "(none)". Exception occurred while: while resolving. Exception is: InvalidOperationException - Could not execute the method because either the method itself or the containing type is not fully instantiated.
----------------------------------------------- At the time of the exception, the container was:
  Resolving ConsoleApplication1Unity.ISample`1[T][],(none)

3 ответа

Решение

Я выполнил задачу создания следующего ExtensionMethod

public static IEnumerable<object> ResolveAllOpenGeneric(this IUnityContainer container, Type openGenericType)
{
    if (!openGenericType.IsGenericTypeDefinition)
        throw new ArgumentNullException("argument must be open generic type");

    return container.Registrations.Where(c =>
                                            c.RegisteredType.IsGenericType
                                            && c.RegisteredType.GetGenericTypeDefinition() == openGenericType
                                        )
                                        .Select(r =>
                                                    container.Resolve(r.RegisteredType, r.Name)
                                        );
}

public static IEnumerable<T> ResolveAllOpenGeneric<T>(this IUnityContainer container, Type openGenericType)
{
    if (!openGenericType.IsGenericTypeDefinition)
        throw new ArgumentNullException("argument must be open generic type");

    return container.Registrations.Where(c =>
                                             c.RegisteredType.IsGenericType
                                             && c.RegisteredType.GetGenericTypeDefinition() == openGenericType
                                         )
                                         .Select(r =>
                                                     (T)container.Resolve(r.RegisteredType, r.Name)
                                         );
}

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

var registrations = container.Registrations
                   .Where(x => x.RegisteredType.IsGenericType && 
                               x.RegisteredType.GetGenericTypeDefinition() == typeof(ISample<>))
                   .ToList();

Это даст вам список всех регистраций. Чтобы получить коллекцию объектов класса, вам просто нужно вызвать Resolve на каждую регистрацию возвращается.

var classList = new List<object>();
foreach (var registration in registrations)
{
    var classObject = container.Resolve(registration.RegisteredType, registration.Name);
    classList.Add(classObject);
}

Единственный тип List<T> который может содержать как ISample<int> а также ISample<string> является object, List<ISample<object>> не будет работать. Если вы переписали интерфейс, чтобы быть

interface ISample { }
interface ISample<out T> : ISample { }

Это делает код намного проще, и вы получаете лучший объект в списке, который позволит вам получить доступ к свойствам и методам ISample это не зависело от T,

var registrations = container.Registrations
                   .Where(x => typeof(ISample).IsAssignableFrom(x.RegisteredType));

var classList = new List<ISample>();
foreach (var registration in registrations)
{
    var classObject = container.Resolve(registration.RegisteredType, registration.Name);
    classList.Add((ISample)classObject);
}

PS Просто чтобы было понятно, что встроено в ResolveAll делает, это в основном

public IEnumerable<object> ResolveAll(Type t, params ResolverOverride[] resolverOverrides)
{
    var registrations = this.Registrations.Where(x => x.RegisteredType == t);
    foreach (var registration in registrations)
    {
        if(registration.Name != null)
            yield return this.Resolve(registration.RegisteredType, registration.Name, resolverOverrides)
    }
}

ISample<> не является допустимым типом для Unity; Вы не можете зарегистрировать его и не можете использовать ResolveAll для получения всех типов, использующих его. Если вы посмотрите на то, что ResolveAll возвращает, это поможет показать проблему. В этом случае он вернул бы IEnumerable>, что недопустимо.

Я не совсем уверен, что вы пытаетесь сделать, поэтому я не знаю, что рекомендовать попробовать.

Другие вопросы по тегам