C# 如何从MEF容器未实例化的对象导出部件 介绍
ClassC# 如何从MEF容器未实例化的对象导出部件 介绍,c#,mef,C#,Mef,ClassSessionModel是一个提供多种服务的服务定位器(我将在将来详细阐述我的系统架构,但现在我需要这样做) 代码 我将以下代码部分编辑为简短、自包含、正确(可编译)的示例(SSCCE): 使用系统; 使用System.ComponentModel.Composition; 使用System.ComponentModel.Composition.Hosting; 命名空间控制台应用程序1 { 内部课程计划 { 私有静态void Main(字符串[]args) { var session
SessionModel
是一个提供多种服务的服务定位器(我将在将来详细阐述我的系统架构,但现在我需要这样做)
代码
我将以下代码部分编辑为简短、自包含、正确(可编译)的示例(SSCCE):
使用系统;
使用System.ComponentModel.Composition;
使用System.ComponentModel.Composition.Hosting;
命名空间控制台应用程序1
{
内部课程计划
{
私有静态void Main(字符串[]args)
{
var sessionModel=新sessionModel(3);
//第一种情况(见下文):
var compositionContainer=新的compositionContainer();
//第二种情况(见下文):
//var typeCatalog=新的typeCatalog(typeof(SessionModel));
//var compositionContainer=新的compositionContainer(类型目录);
compositionContainer.ComposeExportedValue(sessionModel);
var someService=compositionContainer.GetExportedValue();
someService.DoSomething();
}
}
公共类会话模型
{
私有int AValue{get;set;}
[出口]
公共服务SomeService{get;private set;}
公共会话模型(int aValue)
{
AValue=AValue;
//当然,在现实中还有很多事情要做:
SomeService=新的SomeService();
}
}
公共接口服务
{
无效剂量();
}
公共类SomeService:ISomeService
{
公共无效剂量测定法()
{
控制台。WriteLine(“称为DoSomething”);
}
}
}
问题
<>我希望MEF考虑服务定位器在编写其他部件时导出的部分(即<代码> SooService < /代码>),但不幸的是这不起作用。
第一例
当我尝试获取ISomeService
的导出值时,有一个System.ComponentModel.Composition.ImportCardinalistMatchException
告诉我没有具有此合同名称和所需类型标识的导出(ConsoleApplication1.ISomeService
)
第二种情况
如果使用TypeCatalog
创建CompositionContainer
,则例外情况略有不同。这是一个系统.ComponentModel.Composition.CompositionException
告诉我MEF找不到创建控制台应用程序1.SessionModel
(这是正确的,也是我自己这么做的原因)
补充资料
mefx
对这两种情况都说明:
[Part] ConsoleApplication1.SessionModel from: DirectoryCatalog (Path=".")
[Export] ConsoleApplication1.SessionModel.SomeService (ContractName="ConsoleApplication1.ISomeService")
[Part] ConsoleApplication1.SessionModel from: AssemblyCatalog (Assembly="ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
[Export] ConsoleApplication1.SessionModel.SomeService (ContractName="ConsoleApplication1.ISomeService")
我该怎么办?这在MEF中是可能的,还是我必须使用Unity或StructureMap,或者其他什么?这可以通过实现一个
导出提供者来实现吗?问题是SomeService是一个实例属性。您的系统中可能有几个SessionModel对象,而MEF无法知道哪个SessionModel正在返回应该与导入匹配的ISomeService实例
相反,只需将SessionModel设置为静态类,将SomeService设置为静态属性。或者,将SessionModel设置为单例。SomeService属性仍然是静态的,但会从SessionModel的唯一实例导出服务。使用System;
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.ReflectionModel;
using System.Reflection;
using System.Linq;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
var catalogs = new AggregateCatalog();
var catalog = new System.ComponentModel.Composition.Hosting.AssemblyCatalog(Assembly.GetExecutingAssembly());
catalogs.Catalogs.Add(catalog);
var sessionModel = new SessionModel(3);
var container = new CompositionContainer(catalog);
ISomeService someService = container.GetExportedValueOrDefault<ISomeService>(sessionModel.cname);
if (someService != null)
{
someService.DoSomething();
}
}
}
public class SessionModel
{
private int AValue { get; set; }
//[Import("One",typeof(ISomeService))]
//public ISomeService SomeService { get; private set; }
public SessionModel(int aValue)
{
AValue = aValue;
// of course, there is much more to do here in reality:
}
public string cname { get { return "One"; } }
}
public class SessionModel1
{
private int AValue { get; set; }
//[Import("Two",typeof(ISomeService))]
//public ISomeService SomeService { get; private set; }
public SessionModel1(int aValue)
{
AValue = aValue;
}
public string cname { get { return "Two"; } }
}
public interface ISomeService
{
void DoSomething();
}
[Export("One",typeof(ISomeService))]
public class SomeService : ISomeService
{
public SomeService()
{
Console.WriteLine("Some Service Called");
}
public void DoSomething()
{
Console.WriteLine("DoSomething called");
Console.ReadKey();
}
}
[Export("Two",typeof(ISomeService))]
public class SomeService1 : ISomeService
{
public SomeService1()
{
Console.WriteLine("Some Service1 Called");
}
public void DoSomething()
{
Console.WriteLine("DoSomething called 1");
Console.ReadKey();
}
}
}
使用System.ComponentModel.Composition;
使用System.ComponentModel.Composition.Hosting;
使用System.ComponentModel.Composition.ReflectionModel;
运用系统反思;
使用System.Linq;
命名空间控制台应用程序1
{
内部课程计划
{
私有静态void Main(字符串[]args)
{
var catalogs=new AggregateCatalog();
var catalog=new System.ComponentModel.Composition.Hosting.AssemblyCatalog(Assembly.getExecutionGassembly());
目录.目录.添加(目录);
var sessionModel=新sessionModel(3);
var容器=新的合成容器(目录);
ISomeService someService=container.GetExportedValueOrDefault(sessionModel.cname);
if(someService!=null)
{
someService.DoSomething();
}
}
}
公共类会话模型
{
私有int AValue{get;set;}
//[导入(“一”,类型(服务))]
//公共服务SomeService{get;private set;}
公共会话模型(int aValue)
{
AValue=AValue;
//当然,在现实中还有很多事情要做:
}
公共字符串cname{get{返回“一”;}
}
公共类会话模型1
{
私有int AValue{get;set;}
//[导入(“两个”,类型(服务))]
//公共服务SomeService{get;private set;}
公共会话模型1(int aValue)
{
AValue=AValue;
}
公共字符串cname{get{return“Two”;}
}
公共接口服务
{
无效剂量();
}
[导出(“一”,类型(服务))]
公共类SomeService:ISomeService
{
公共服务
{
WriteLine(“一些被调用的服务”);
}
公共无效剂量测定法()
{
控制台。WriteLine(“称为DoSomething”);
Console.ReadKey();
}
}
[导出(“两个”,类型(服务))]
公共类SomeService1:ISomeService
{
公共服务1()
{
Console.WriteLine(“调用的某些服务”);
}
公共无效剂量测定法()
{
控制台。WriteLine(“DoSomething称为1”);
Console.ReadKey();
}
}
}
第一种情况:通过将会话模型
传递到ComposeExportedValue
可以添加类型为会话模型
的一部分,而不是的一部分
compositionContainer.ComposeExportedValue(sessionModel.SomeService);
public class SessionModelExportProvider : ExportProvider
{
private List<Export> Exports { get; set; }
public SessionModelExportProvider(SessionModel sessionModel)
{
// get all the properties of the session model having an Export attribute
var typeOfSessionModel = typeof (SessionModel);
PropertyInfo[] properties = typeOfSessionModel.GetProperties();
var propertiesHavingAnExportAttribute =
from p in properties
let exportAttributes = p.GetCustomAttributes(typeof (ExportAttribute), false)
where exportAttributes.Length > 0
select new
{
PropertyInfo = p,
ExportAttributes = exportAttributes
};
// creating Export objects for each export
var exports = new List<Export>();
foreach (var propertyHavingAnExportAttribute in propertiesHavingAnExportAttribute)
{
var propertyInfo = propertyHavingAnExportAttribute.PropertyInfo;
foreach (ExportAttribute exportAttribute in propertyHavingAnExportAttribute.ExportAttributes)
{
string contractName = exportAttribute.ContractName;
if (string.IsNullOrEmpty(contractName))
{
Type contractType = exportAttribute.ContractType ?? propertyInfo.PropertyType;
contractName = contractType.FullName;
}
var metadata = new Dictionary<string, object>
{
{CompositionConstants.ExportTypeIdentityMetadataName, contractName},
{CompositionConstants.PartCreationPolicyMetadataName, CreationPolicy.Shared}
};
var exportDefinition = new ExportDefinition(contractName, metadata);
var export = new SessionModelExport(sessionModel, propertyInfo, exportDefinition);
exports.Add(export);
}
}
Exports = exports;
}
protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition,
AtomicComposition atomicComposition)
{
return Exports.Where(e => definition.IsConstraintSatisfiedBy(e.Definition));
}
}
public class SessionModelExport : Export
{
private readonly SessionModel sessionModel;
private readonly PropertyInfo propertyInfo;
private readonly ExportDefinition definition;
public SessionModelExport(SessionModel sessionModel, PropertyInfo propertyInfo, ExportDefinition definition)
{
this.sessionModel = sessionModel;
this.propertyInfo = propertyInfo;
this.definition = definition;
}
public override ExportDefinition Definition
{
get { return definition; }
}
protected override object GetExportedValueCore()
{
var value = propertyInfo.GetValue(sessionModel, null);
return value;
}
}