ServiceStack IContainerAdapter, адаптирующий Autofa c версии 5.2.0 - PullRequest
1 голос
/ 26 мая 2020

Я пытаюсь обновить последний пакет Autofa c до 5.2.0, но не очень успешно из-за изменений интерфейса,

From (Autofac 4.9.4)

public static class ResolutionExtensions
{
    public static bool TryResolve<T>(this IComponentContext context, out T instance);
}

Кому (Autofac 5.2.0)

public static class ResolutionExtensions
{
    public static bool TryResolve<T>(this IComponentContext context, out T instance) 
        where T : class;
}    

Пакет ServiceStack имеет интерфейс IContainerAdapter (ServiceStack.Interfaces 5.8.0)

public interface IResolver
{
    T TryResolve<T>();
}  

public interface IContainerAdapter : IResolver
{
    T Resolve<T>();
}

Мой AutofacIocAdapter реализует этот IContainerAdapter

public class AutofacIocAdapter : IContainerAdapter
{
    public T TryResolve<T>()
    {
        if (m_Container.TryResolve<Autofac.ILifetimeScope>(out var scope) &&
            scope.TryResolve<T>(out var scopeComponent))
        {
            return scopeComponent;
        }

        if (m_Container.TryResolve<T>(out var component))
        {
            return component;
        }

        return default(T);
    }
}

Но после обновления произошла ошибка компиляции Autofa c

Error   CS0452  The type 'T' must be a reference type in order to use it as parameter 'T' in the generic type or method 'ResolutionExtensions.TryResolve<T>(IComponentContext, out T?)'

Есть предложения по разрешению?

1 Ответ

1 голос
/ 26 мая 2020

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

Но ваша первая попытка должна состоять в обойти API с ограничением. Глядя на реализацию TryResolve AutoFa c, вы увидите, какие API-интерфейсы они вызывают внутренне:

public static bool TryResolve<T>(this IComponentContext context, out T? instance)
    where T : class
{
    if (context == null)
    {
        throw new ArgumentNullException(nameof(context));
    }

    object? component;

    // Null annotation attributes only work if placed directly in an if statement.
    if (context.TryResolve(typeof(T), out component))
    {
        instance = (T)component;

        return true;
    }
    else
    {
        instance = default;

        return false;
    }
}

Таким образом, вам просто нужно обойти их общий c API с ограничениями и вызывают тот же API типов среды выполнения, который они вызывают, например:

public class AutofacIocAdapter : IContainerAdapter
{
    private readonly Autofac.IContainer container;

    public AutofacIocAdapter(Autofac.IContainer container) => 
        this.container = container;

    public T TryResolve<T>()
    {
        if (container.TryResolve<Autofac.ILifetimeScope>(out var scope) &&
            scope.TryResolve(typeof(T), out var scopeComponent))
            return (T)scopeComponent;

        if (container.TryResolve(typeof(T), out var component))
            return (T)component;

        return default;
    }

    public T Resolve<T>()
    {
        var ret = TryResolve<T>();
        return !ret.Equals(default)
            ? ret
            : throw new Exception($"Error trying to resolve '{typeof(T).Name}'");
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...