C# MEF 构造函数注入
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2008133/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MEF Constructor Injection
提问by alpha
I'm trying to figure out MEF's Constructor Injection attribute. I have no idea how I tell it to load the constructor's parameters.
我试图找出 MEF 的构造函数注入属性。我不知道如何告诉它加载构造函数的参数。
This is the property I'm trying to load
这是我正在尝试加载的属性
[ImportMany(typeof(BUsers))]
public IEnumerable<BUsers> LoadBUsers { get; set; }
Here is the code I'm using to import the assemblies.
这是我用来导入程序集的代码。
try
{
var catalog = new AggregateCatalog();
catalog.Catalogs.Add(new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()));
catalog.Catalogs.Add(new DirectoryCatalog("DI"));
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
Here is the class I'm trying to load
这是我正在尝试加载的课程
[Serializable]
[Export(typeof(BUsers))]
public class EditProfile : BUsers
{
[ImportingConstructor]
public EditProfile(string Method, string Version)
{
Version = "2";
Action = "Edit";
TypeName = "EditProfile";
}
采纳答案by Daniel Plaisted
When you use the ImportingConstructor attribute, the parameters to the constructor become imports. By default, what you are importing (the contract name) is based on the type of the parameter or property that your are importing into. So in this case the contract type for both your imports is string, and there's no real difference between the first and second parameter.
当您使用 ImportingConstructor 属性时,构造函数的参数变为导入。默认情况下,您要导入的内容(合同名称)基于您要导入的参数或属性的类型。因此,在这种情况下,您的两个导入的合同类型都是字符串,第一个和第二个参数之间没有真正的区别。
It looks like you are trying to use imports to supply configuration values, which isn't necessarily what it was designed for. To get it to do what you want, you should override the contract name for each of the parameters, like this:
看起来您正在尝试使用导入来提供配置值,这不一定是它的设计目的。为了让它做你想做的事,你应该覆盖每个参数的合同名称,如下所示:
[ImportingConstructor]
public EditProfile([Import("Method")] string Method, [Import("Version")] string Version)
{ }
Then you need exports for Method and Version in your container. One way to do this is just to add them directly:
然后,您需要导出容器中的方法和版本。一种方法是直接添加它们:
var container = new CompositionContainer(catalog);
container.ComposeExportedValue("Method", "MethodValue");
container.ComposeExportedValue("Version", "2.0");
container.ComposeParts(this);
(Note that ComposeExportedValue is actually an extension method defined on the static AttributedModelServices class.)
(注意 ComposeExportedValue 实际上是在静态 AttributedModelServices 类上定义的扩展方法。)
If you want to read these values from a configuration file of some sort, you could create your own export provider which reads the configuration and provides the values in it as exports to the container.
如果您想从某种配置文件中读取这些值,您可以创建自己的导出提供程序,它读取配置并将其中的值作为导出到容器提供。
An alternative way to handle this would be to just import an interface that provides access to the configuration values by name, and get the values you need from the body of the constructor.
处理此问题的另一种方法是仅导入一个接口,该接口提供按名称访问配置值的权限,并从构造函数的主体中获取您需要的值。
回答by David.Chu.ca
I like Daniel's solution; however, only one thing I see is the tight coupling of parameter names between the actor (who creates CompopositionContrainer()) and Export part with [ImportingConstructor] for customized CTOR. For example, "Method" has two be matched in both places. It makes hard to maintain the Export part if the actor and Export part are in difference projects.
我喜欢丹尼尔的解决方案;然而,我看到的只有一件事是演员(创建 CompopositionContrainer())和导出部分与 [ImportingConstructor] 之间的参数名称的紧密耦合,用于自定义 CTOR。例如,“方法”在两个地方都有两个匹配。如果演员和导出部分在不同的项目中,则很难维护导出部分。
If it is possible, I would add the second CTOR to the Export part class. For example:
如果可能,我会将第二个 CTOR 添加到导出部件类。例如:
[Export(typeof(BUsers))]
public class EditProfile : BUsers
{
[ImportingConstructor]
public EditProfile(EditProfileParameters ctorPars)
: this(ctorPars.Method, ctorPars.Version) {}
public EditProfile(string Method, string Version)
{
Version = "2";
Action = "Edit";
TypeName = "EditProfile";
}
The class of EditProfileParameters should be straightforward: two properties of Method and Version:
EditProfileParameters 类应该很简单:Method 和 Version 两个属性:
[Export]
public class EditProfileParameters{
public string Method { get; set; }
public string Version { get; set; }
}
The key point is to add Export attribute to the class. Then MEF should be able to map this class to the parameter of EditProfile's CTOR.
关键点是将Export 属性添加到类中。那么 MEF 应该能够将这个类映射到 EditProfile 的 CTOR 的参数上。
Here is example to add the Export part to container:
以下是将导出部分添加到容器的示例:
var container = new CompositionContainer(catalog);
var instance1 = new EditProfileParameters();
// set property values from config or other resources
container.ComposeExportedValue(instance1);
container.ComposeParts(this);
回答by bryanbcook
Although late to the game, here's another approach that leverages a lesser-known feature of MEF: Property Exports
尽管游戏起步较晚,但这里有另一种利用 MEF 鲜为人知的功能的方法:属性导出
public class ObjectMother
{
[Export]
public static EditProfile DefaultEditProfile
{
get
{
var method = ConfigurationManager.AppSettings["method"];
var version = ConfigurationManager.AppSettings["version"];
return new EditProfile(method,version);
}
}
}
No usages are required for ObjectMother for this to work, and no attributes are required on EditProfile.
ObjectMother 不需要任何用法即可使其工作,并且 EditProfile 上不需要任何属性。