如何使用 autofac 通过字符串解析 class 与第 3 方通用接口
How can I resolve a class with 3rd party generic interface by string using autofac
在 autofac 中注册了不同的 classes,它们具有相同的通用接口,但使用不同的 class 模型。我需要的是在不知道 class 模型的情况下用字符串解析 class 。我不确定它是否可以轻松实现。请有任何建议。
我正在使用控制台应用程序,但我不知道 class 模型,因为我们收到了一个字符串。我已经在开始 class 中注册了所有 class,但我想在不知道 class 模型的情况下解析 class。我不想使用 if else 来表示 if string == "something" then resolve this else if resolve this。我正在寻找最佳实践。
public TestModel1 { }
public TestModel2 { }
public interface ICalculator<string, T> {}
public Impl1: ICalculator<string, TestModel1> {}
public Impl2: ICalculator<string, TestModel2> {}
在 Autofac 中我注册为:
builder.Register<Impl1>.As<ICalculator<string, TestModel1>>();
builder.Register<Impl2>.As<ICalculator<string, TestModel2>>();
在控制台应用程序中,我想执行如下操作:
container.Resolve 按字符串而不是像
if (...) {
class = container.resolve<ICalculator<string, TestModel1>>()
} else {
class = container.resolve<ICalculator<string, TestModel2>>()
}
我希望能够在控制台应用程序中执行类似的操作:
var class = container.resolve<ICalculator>("pass string");
AFAIK 你只能解决你注册的问题。所以你不能从 ICalculator<string, TestModel2>
得到 ICalculator
因为这是两个非常不同的接口。
使用Named Services。你可以这样做:
假设:
public class Impl1 : ICalculator<string, TestModel1> {}
public class Impl2 : ICalculator<string, TestModel1> {}
// Notice these are the same ---------------------^
// If these need to be different use #2 (Below)
注册:
builder.Register<Impl1>.Named<ICalculator<string, TestModel1>>("pass string1");
builder.Register<Impl2>.Named<ICalculator<string, TestModel1>>("pass string2");
// Notice these are the same ------------------------------^
通过以下方式解决:
var r = container.resolve<ICalculator<string, TestModel1>>("pass string2)
// = Impl2
或 2.
首先创建一个基础接口:
public interface ICalculator {}
public interface ICalculator<T1, T2> : ICalcuator;
public class Impl1 : ICalculator<string, TestModel1> {}
public class Impl2 : ICalculator<string, TestModel2> {}
注册:
builder.Register<Impl1>.Named<ICalculator>("pass string1");
builder.Register<Impl2>.Named<ICalculator>("pass string2");
已通过
解决
var r = container.resolve<ICalculator>("pass string2)
// = Impl2
如果您的控制台应用程序(或真实应用程序)非常复杂,您真的应该考虑使用作用域来帮助控制对象的生命周期:
builder
.Register<Impl1>
.Named<ICalculator<string, TestModel1>>("pass string1")
.InstancePerLifetimeScope();
builder
.Register<Impl2>
.Named<ICalculator<string, TestModel1>>("pass string2")
.InstancePerLifetimeScope();
然后
using (scope1 = container.BeginLifetimeScope())
{
var r = scope1.Resolve<ICalculator>("pass string1");
// r would be disposed if it implemented IDisposable
// before scope1 is `Disposed()`
}
However, the problem I face is that the interface is coming from a library developed by another team.
在那种情况下,您可以尝试注册泛型,并让 DI 在解析时而不是在实现期间知道泛型类型:
// @nuget: Autofac
using System;
using Autofac;
public class Program
{
private static IContainer _Container;
public static void Main()
{
var builder = new ContainerBuilder();
builder
.RegisterGeneric(typeof (Impl1<, >))
.Named("pass string1", typeof (Calculator3rdParty<, >))
.InstancePerLifetimeScope();
builder
.RegisterGeneric(typeof (Impl2<, >))
.Named("pass string2", typeof (Calculator3rdParty<, >))
.InstancePerLifetimeScope();
_Container = builder.Build();
using (var scope = _Container.BeginLifetimeScope())
{
var c3p = scope
.ResolveNamed<Calculator3rdParty<string, Model1>>("pass string2");
// specify type at resolve ----------^
Console.WriteLine(c3p.GetType());
}
}
}
public interface Calculator3rdParty<T1, T2>{}
public class Model1{}
public class Model2{}
public class Impl1<T1, T2> : Calculator3rdParty<T1, T2>{}
public class Impl2<T1, T2> : Calculator3rdParty<T1, T2>{}
输出:
Impl2`2[System.String,Model1]
在 autofac 中注册了不同的 classes,它们具有相同的通用接口,但使用不同的 class 模型。我需要的是在不知道 class 模型的情况下用字符串解析 class 。我不确定它是否可以轻松实现。请有任何建议。
我正在使用控制台应用程序,但我不知道 class 模型,因为我们收到了一个字符串。我已经在开始 class 中注册了所有 class,但我想在不知道 class 模型的情况下解析 class。我不想使用 if else 来表示 if string == "something" then resolve this else if resolve this。我正在寻找最佳实践。
public TestModel1 { }
public TestModel2 { }
public interface ICalculator<string, T> {}
public Impl1: ICalculator<string, TestModel1> {}
public Impl2: ICalculator<string, TestModel2> {}
在 Autofac 中我注册为:
builder.Register<Impl1>.As<ICalculator<string, TestModel1>>();
builder.Register<Impl2>.As<ICalculator<string, TestModel2>>();
在控制台应用程序中,我想执行如下操作: container.Resolve 按字符串而不是像
if (...) {
class = container.resolve<ICalculator<string, TestModel1>>()
} else {
class = container.resolve<ICalculator<string, TestModel2>>()
}
我希望能够在控制台应用程序中执行类似的操作:
var class = container.resolve<ICalculator>("pass string");
AFAIK 你只能解决你注册的问题。所以你不能从 ICalculator<string, TestModel2>
得到 ICalculator
因为这是两个非常不同的接口。
使用Named Services。你可以这样做:
假设:
public class Impl1 : ICalculator<string, TestModel1> {}
public class Impl2 : ICalculator<string, TestModel1> {}
// Notice these are the same ---------------------^
// If these need to be different use #2 (Below)
注册:
builder.Register<Impl1>.Named<ICalculator<string, TestModel1>>("pass string1");
builder.Register<Impl2>.Named<ICalculator<string, TestModel1>>("pass string2");
// Notice these are the same ------------------------------^
通过以下方式解决:
var r = container.resolve<ICalculator<string, TestModel1>>("pass string2)
// = Impl2
或 2.
首先创建一个基础接口:
public interface ICalculator {}
public interface ICalculator<T1, T2> : ICalcuator;
public class Impl1 : ICalculator<string, TestModel1> {}
public class Impl2 : ICalculator<string, TestModel2> {}
注册:
builder.Register<Impl1>.Named<ICalculator>("pass string1");
builder.Register<Impl2>.Named<ICalculator>("pass string2");
已通过
解决var r = container.resolve<ICalculator>("pass string2)
// = Impl2
如果您的控制台应用程序(或真实应用程序)非常复杂,您真的应该考虑使用作用域来帮助控制对象的生命周期:
builder
.Register<Impl1>
.Named<ICalculator<string, TestModel1>>("pass string1")
.InstancePerLifetimeScope();
builder
.Register<Impl2>
.Named<ICalculator<string, TestModel1>>("pass string2")
.InstancePerLifetimeScope();
然后
using (scope1 = container.BeginLifetimeScope())
{
var r = scope1.Resolve<ICalculator>("pass string1");
// r would be disposed if it implemented IDisposable
// before scope1 is `Disposed()`
}
However, the problem I face is that the interface is coming from a library developed by another team.
在那种情况下,您可以尝试注册泛型,并让 DI 在解析时而不是在实现期间知道泛型类型:
// @nuget: Autofac
using System;
using Autofac;
public class Program
{
private static IContainer _Container;
public static void Main()
{
var builder = new ContainerBuilder();
builder
.RegisterGeneric(typeof (Impl1<, >))
.Named("pass string1", typeof (Calculator3rdParty<, >))
.InstancePerLifetimeScope();
builder
.RegisterGeneric(typeof (Impl2<, >))
.Named("pass string2", typeof (Calculator3rdParty<, >))
.InstancePerLifetimeScope();
_Container = builder.Build();
using (var scope = _Container.BeginLifetimeScope())
{
var c3p = scope
.ResolveNamed<Calculator3rdParty<string, Model1>>("pass string2");
// specify type at resolve ----------^
Console.WriteLine(c3p.GetType());
}
}
}
public interface Calculator3rdParty<T1, T2>{}
public class Model1{}
public class Model2{}
public class Impl1<T1, T2> : Calculator3rdParty<T1, T2>{}
public class Impl2<T1, T2> : Calculator3rdParty<T1, T2>{}
输出:
Impl2`2[System.String,Model1]