首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >对连接字符串的Autofac支持

对连接字符串的Autofac支持
EN

Code Review用户
提问于 2020-01-05 06:02:51
回答 1查看 576关注 0票数 1

我希望Autofac以URI的形式基于连接字符串实例化组件:

代码语言:javascript
复制
autofac://assembly-name/full-class-name?param1=arg1¶m2=arg2 

因此,下面的测试将有效:

代码语言:javascript
复制
[TestClass]
public class Locator_Should
{
    [TestMethod]
    public void Resolve()
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<DiskFolder>();
        var container = builder.Build();
        var folder = container.Resolve<IFolder>(
            "autofac://LocatorTest/LocatorTest.DiskFolder?path=\\Windows");

        Assert.IsTrue(folder.Any());
    }
}

其中:

代码语言:javascript
复制
public interface IFolder : IEnumerable<string>
{
}

public class DiskFolder : ReadOnlyCollection<string>, IFolder
{
    public DiskFolder(string path)
        : base(Directory.GetFiles(path))
    {
    }
}

图书馆代码是:

代码语言:javascript
复制
public static class AutofacLocator
{
    public static T Resolve<T>(this ILifetimeScope scope, string uri) =>
        scope.Resolve<T>(new Uri(uri));

    public static object Resolve(this ILifetimeScope scope, string uri) =>
        scope.Resolve(new Uri(uri));

    public static T Resolve<T>(this ILifetimeScope scope, Uri uri) =>
        (T)scope.Resolve(uri);

    public static object Resolve(this ILifetimeScope scope, Uri uri)
    {
        if (uri.Scheme != "autofac")
            throw new NotSupportedException("Schema not supported.");

        var factory = (Delegate)scope.Resolve(GetFactory(uri));
        return factory.DynamicInvoke(GetArguments(uri));
    }

    static Type GetFactory(Uri uri)
    {
        Func<Type[], Type> getType = Expression.GetFuncType;
        var types = GetParameters(uri)
            .Select(p => p.ParameterType)
            .Append(GetReturnType(uri));

        return getType(types.ToArray());
    }

    static object[] GetArguments(Uri uri)
    {
        var arguments = uri.Query
            .TrimStart('?')
            .Split('&')
            .Select(p => p.Split('='))
            .ToDictionary(nv => nv[0], nv => Uri.UnescapeDataString(nv[1]));

        return GetParameters(uri)
            .Select(p => Convert.ChangeType(arguments[p.Name], p.ParameterType))
            .ToArray();
    }

    static ParameterInfo[] GetParameters(Uri uri) =>
        GetReturnType(uri)
            .GetConstructors()
            .First()
            .GetParameters();

    static Type GetReturnType(Uri uri) =>
        Type.GetType($"{uri.Segments[1]}, {uri.Host}");
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2020-01-06 18:26:03

这里的目标似乎是使用一种不同的格式(基于字符串的东西)为一个解析操作提供参数。这在服务位置(手动执行Resolve)场景中似乎主要是有用的,而不是真正的DI,所以我要提醒您小心。

因为这是作为Autofac解决方案开始的,我将基于Autofac发布一个答案。

我的第一个建议是实现一个newParametertype,而不是完全单独处理字符串。这将使该解决方案与其他参数类型和Autofac整体上更加可互操作。您可以看到其他参数类型(如ResolvedParameterNamedParameter )是如何实现的,给出了示例。

我的第二个建议是去查看Autofac.Configuration如何处理将字符串值解析为对象的方法。Convert.ChangeType在很多事情上不起作用,有一个更健壮的机制是很有价值的。

终于..。如果可能的话,我可能会考虑看一下需要这样做的设计,看看是否可以更改。正如我所提到的,这在服务位置上似乎主要是有用的,如果您可以切换解决方案来使用实际的依赖注入,那就更好了。这意味着参数需要在注册时可用(例如,在注册时从config读取它们并包含它们的值);或者在运行时,您可能会在消费类中使用解出Func或者类似的东西,而不是使用生存期范围。在这两种情况下,一旦切换到DI,这种机制的效用就会受到限制。可能仅仅使用Autofac.Configuration就足够了。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/235102

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档