ServiceStack IContainerAdapter适配Autofac 5.2.0版本

ServiceStack IContainerAdapter adapting Autofac 5.2.0 version

我正在尝试将最新的 Autofac 软件包升级到 5.2.0,但由于界面更改而没有真正成功,

来自(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);
    }
}

但是升级后出现编译错误Autofac

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?)'

有什么建议可以解决吗?

如果没有来自 C# 的约束,您将无法调用带有 class 约束的 class,但您可以使用反射来调用它。

但是您的第一次尝试应该是绕过带有约束的 API。查看 AutoFac's implementation of TryResolve 将显示他们在内部调用的 APIs:

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;
    }
}

因此,您只需要绕过带有约束的通用 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}'");
    }
}