我希望Autofac以URI的形式基于连接字符串实例化组件:
autofac://assembly-name/full-class-name?param1=arg1¶m2=arg2 因此,下面的测试将有效:
[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());
}
}其中:
public interface IFolder : IEnumerable<string>
{
}
public class DiskFolder : ReadOnlyCollection<string>, IFolder
{
public DiskFolder(string path)
: base(Directory.GetFiles(path))
{
}
}图书馆代码是:
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}");
}发布于 2020-01-06 18:26:03
这里的目标似乎是使用一种不同的格式(基于字符串的东西)为一个解析操作提供参数。这在服务位置(手动执行Resolve)场景中似乎主要是有用的,而不是真正的DI,所以我要提醒您小心。
因为这是作为Autofac解决方案开始的,我将基于Autofac发布一个答案。
我的第一个建议是实现一个newParametertype,而不是完全单独处理字符串。这将使该解决方案与其他参数类型和Autofac整体上更加可互操作。您可以看到其他参数类型(如ResolvedParameter和NamedParameter )是如何实现的,给出了示例。
我的第二个建议是去查看Autofac.Configuration如何处理将字符串值解析为对象的方法。。Convert.ChangeType在很多事情上不起作用,有一个更健壮的机制是很有价值的。
终于..。如果可能的话,我可能会考虑看一下需要这样做的设计,看看是否可以更改。正如我所提到的,这在服务位置上似乎主要是有用的,如果您可以切换解决方案来使用实际的依赖注入,那就更好了。这意味着参数需要在注册时可用(例如,在注册时从config读取它们并包含它们的值);或者在运行时,您可能会在消费类中使用解出Func或者类似的东西,而不是使用生存期范围。在这两种情况下,一旦切换到DI,这种机制的效用就会受到限制。可能仅仅使用Autofac.Configuration就足够了。
https://codereview.stackexchange.com/questions/235102
复制相似问题