gpt4 book ai didi

c# - 如何从未由 MEF 容器实例化的对象中导出部件

转载 作者:太空狗 更新时间:2023-10-29 21:58:15 24 4
gpt4 key购买 nike

简介

SessionModel 是一个提供多种服务的服务定位器(我将在未来详细阐述我的系统架构,但现在我需要那样做)。

代码

我将以下代码部分编辑为简短、自包含、正确(可编译)示例 (SSCCE):

using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
var sessionModel = new SessionModel(3);

// first case (see text down below):
var compositionContainer = new CompositionContainer();

// second case (see text down below):
//var typeCatalog = new TypeCatalog(typeof (SessionModel));
//var compositionContainer = new CompositionContainer(typeCatalog);

compositionContainer.ComposeExportedValue(sessionModel);

var someService = compositionContainer.GetExportedValue<ISomeService>();
someService.DoSomething();
}
}

public class SessionModel
{
private int AValue { get; set; }

[Export]
public ISomeService SomeService { get; private set; }

public SessionModel(int aValue)
{
AValue = aValue;
// of course, there is much more to do here in reality:
SomeService = new SomeService();
}
}

public interface ISomeService
{
void DoSomething();
}

public class SomeService : ISomeService
{
public void DoSomething()
{
Console.WriteLine("DoSomething called");
}
}
}

问题

我希望 MEF 在组合其他部分时考虑服务定位器导出的部分(即 SomeService),但不幸的是,这不起作用。

第一个案例

当我尝试获取 ISomeService 的导出值时,有一个 System.ComponentModel.Composition.ImportCardinalityMismatchException 告诉我没有具有此契约(Contract)名称和所需类型的导出身份(ConsoleApplication1.ISomeService)。

第二种情况

如果我使用 TypeCatalog 创建 CompositionContainer,异常会略有不同。这是一个 System.ComponentModel.Composition.CompositionException 告诉我 MEF 没有找到创建 ConsoleApplication1.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 或其他东西?这可以通过实现 ExportProvider 来完成吗?

最佳答案

好的,我就是这样做的:

我实现了自己的 SessionModelExportProvider 在我的 SessionModel 中查找导出(参见下面的代码)。 SessionModelExport 类仅用于保存导出数据,而不是创建服务实例 - 返回 SessionModel 的属性值。

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;
}
}

关于c# - 如何从未由 MEF 容器实例化的对象中导出部件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17945124/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com