我目前正在我的项目中使用MEF,但是,遗留组件使用Castle来导出其所有组件。
我希望能够在创建新对象时从此内核导入,以及从Xap获取导出。
这可能吗?你能告诉我一些示例代码吗?
答案 0 :(得分:2)
MEF旨在尽可能灵活,其中一个秘密隐藏但真正优秀的功能是能够定义新的ExportProvider
实例,允许您插入其他组件。我之前通过在带有MEF项目的ASP.NET MVC中使用Common Service Locator项目来讨论这个问题(参见第3部分here)。
CSL是一种很好的灵活方法,因为许多现有的IoC容器都有许多特定的CSL实现,例如Castle,Autofac,Ninject,Unity等。
可以找到另一个很好的例子here,它展示了一种略有不同但基本相似的方法。
答案 1 :(得分:1)
正如Matthew所说,做到这一点的方法是使用ExportProvider
另一个例子是here(它演示了Xaml的导出)。 以下是我最终解决问题的方法。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Linq;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
using Castle.Windsor;
namespace MEFCastleBridge
{
public class CastleExportProvider : ExportProvider
{
WindsorContainer _container;
private readonly Dictionary<ExportDefinition, List<Export>> _exports =
new Dictionary<ExportDefinition, List<Export>>();
private readonly object _sync = new object();
public CastleExportProvider(WindsorContainer container)
{
_container = container;
var handlers = _container.Kernel.GetAssignableHandlers(typeof(object));
foreach (var handler in handlers)
{
RegisterCastleComponent(handler);
}
_container.Kernel.ComponentRegistered += ComponentRegistered;
}
protected override IEnumerable<Export> GetExportsCore(
ImportDefinition definition, AtomicComposition atomicComposition)
{
var contractDefinition = definition as ContractBasedImportDefinition;
var retVal = Enumerable.Empty<Export>();
if (contractDefinition != null)
{
string contractName = contractDefinition.ContractName;
if (!string.IsNullOrEmpty(contractName))
{
var exports =
from e in _exports
where string.Compare(e.Key.ContractName, contractName, StringComparison.OrdinalIgnoreCase) == 0
select e.Value;
if (exports.Count() > 0)
{
retVal = exports.First();
}
}
}
return retVal;
}
void RegisterCastleComponent(IHandler handler)
{
var type = handler.Service;
var contractName = type.ToString();
lock (_sync)
{
var found = from e in _exports
where string.Compare(e.Key.ContractName,
contractName, StringComparison.OrdinalIgnoreCase) == 0
select e;
if (found.Count() == 0)
{
var metadata = new Dictionary<string, object>();
var definition = new ExportDefinition(contractName, metadata);
_exports.Add(definition, new List<Export>());
}
var wrapper = new Export(contractName, () => _container.Resolve(type));
found.First().Value.Add(wrapper);
}
}
void ComponentRegistered(string key, IHandler handler)
{
RegisterCastleComponent(handler);
}
}
public interface IMyComponent
{
string TheString { get; }
}
public class RegisteredComponent : IMyComponent
{
public string TheString { get { return "RegisteredComponent"; } }
}
[Export(typeof(IMyComponent))]
public class ExportedComponent : IMyComponent
{
public string TheString { get { return "ExportedComponent"; } }
}
public class ExportExample
{
// Will contain an instance of RegisteredComponent and ExportedComponent
[ImportMany]
public List<IMyComponent> Components { get; set; }
public ExportExample()
{
// Create a Windsor container and add a type.
var container = new WindsorContainer();
container.Register(Component.For<IMyComponent>().ImplementedBy<MyComponent>().LifeStyle.Singleton);
// Add the Export Provider, in addition to the DeploymentCatalog
var compContainer = new CompositionContainer(new DeploymentCatalog(), new CastleExportProvider(container));
// Should only be called once, before any attempt to SatisfyImports.
CompositionHost.Initialize(compContainer);
CompositionInitializer.SatisfyImports(this);
Test = string.Join(", ", Components.Select(c => c.DoSomething));
}
public string Test { get; set; }
}
}