首页 > 解决方案 > ServiceStack IContainerAdapter适配Autofac 5.2.0版本

问题描述

我正在尝试将最新的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#servicestackautofac

解决方案


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

但是您的第一次尝试应该是绕过带有约束的 API。查看AutoFac 的 TryResolve 实现将显示它们在内部调用的 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;
    }
}

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

推荐阅读