Created
May 6, 2012 14:15
-
-
Save runceel/2622484 to your computer and use it in GitHub Desktop.
明日のBlog記事ネタ
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
*[WinRT][MEF]WinRTのMEFでServiceLocator実装してみた | |
WinRTのMEFってCompositionContainerクラスがいなくなってCompositionServiceクラスでSatisfyImportsOnceメソッド使って対象クラスに何かをImportするということしかできないっぽいです。なのでMVVM Light 4のDIコンテナにMEF使ってやろうと思ったらいきなり挫折してしまいましたorz | |
それじゃぁ悔しいので、無理やりCompositionServiceクラスを使った状態でIServiceLocatorインターフェースを実装してみました。ちなみにMVVM Light 4に添付されてるMicrosoft.Practices.ServiceLocation.dllを使います。 | |
**実装 | |
ということでさくっと実装してみました。SatisfyImportsOnceメソッドにRegistrationBuilderのインスタンスを渡せば実行時にImportの挙動とかをいじれるみたいなので、それを使ってごにょごにょっとしてます。 | |
>|cs| | |
namespace SampleImplementation | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel.Composition; | |
using System.ComponentModel.Composition.Hosting; | |
using System.ComponentModel.Composition.Primitives; | |
using System.ComponentModel.Composition.Registration; | |
using System.Linq; | |
using System.Reflection; | |
using Microsoft.Practices.ServiceLocation; | |
public class MefServiceLocator : IServiceLocator | |
{ | |
private CompositionService service; | |
public MefServiceLocator(params ComposablePartCatalog[] catalogs) | |
{ | |
// カタログからCompositionServiceを作成 | |
var catalog = new AggregateCatalog(catalogs); | |
this.service = catalog.CreateCompositionService(); | |
} | |
private IEnumerable<object> DoGetAllInstances(Type serviceType) | |
{ | |
// ManyValueHolder<T>型を作成 | |
var holderType = typeof(ManyValueHolder<>).MakeGenericType(serviceType); | |
// ValuesプロパティにImportManyをつけてるイメージ | |
var b = new RegistrationBuilder(); | |
b.ForType(holderType) | |
.ImportProperties(p => true, (p, c) => c.AsMany(true)); | |
// ManyValueHolder<T>型のインスタンスを作成してImport | |
var holderInstance = Activator.CreateInstance(holderType); | |
this.service.SatisfyImportsOnce(holderInstance, b); | |
// Valuesプロパティの値を取得して返却 | |
var valuePropertyInfo = holderType.GetTypeInfo().GetDeclaredProperty("Values"); | |
return (IEnumerable<object>) valuePropertyInfo.GetValue(holderInstance); | |
} | |
private object DoGetInstance(Type serviceType, string key) | |
{ | |
// SingleValueHolder<T>型を作成 | |
var holderType = typeof(SingleValueHolder<>).MakeGenericType(serviceType); | |
// ValueプロパティにImport属性をつけてるイメージ | |
// コントラクト名が指定されている場合はそれも追加する | |
var b = new RegistrationBuilder(); | |
b.ForType(holderType) | |
.ImportProperties(p => true, (p, c) => | |
{ | |
if (!string.IsNullOrEmpty(key)) | |
{ | |
c.AsContractName(key); | |
} | |
}); | |
// SingleValueHolder<T>型のインスタンスを作成してImport | |
var holderInstance = Activator.CreateInstance(holderType); | |
this.service.SatisfyImportsOnce(holderInstance, b); | |
// Valueプロパティの値を取得して返却 | |
var valuePropertyInfo = holderType.GetTypeInfo().GetDeclaredProperty("Value"); | |
return valuePropertyInfo.GetValue(holderInstance); | |
} | |
public IEnumerable<TService> GetAllInstances<TService>() | |
{ | |
return DoGetAllInstances(typeof(TService)).Cast<TService>(); | |
} | |
public IEnumerable<object> GetAllInstances(Type serviceType) | |
{ | |
return DoGetAllInstances(serviceType); | |
} | |
public TService GetInstance<TService>(string key) | |
{ | |
return (TService)DoGetInstance(typeof(TService), key); | |
} | |
public TService GetInstance<TService>() | |
{ | |
return (TService) DoGetInstance(typeof(TService), null); | |
} | |
public object GetInstance(Type serviceType, string key) | |
{ | |
return DoGetInstance(serviceType, key); | |
} | |
public object GetInstance(Type serviceType) | |
{ | |
return DoGetInstance(serviceType, null); | |
} | |
} | |
/// <summary> | |
/// 単一のインスタンスをImportするためのクラス | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
class SingleValueHolder<T> | |
{ | |
public T Value { get; set; } | |
} | |
/// <summary> | |
/// 複数のインスタンスをImportするためのクラス | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
class ManyValueHolder<T> | |
{ | |
public IEnumerable<T> Values { get; set; } | |
} | |
} | |
||< | |
こんな感じで実装完了!通したテストは以下のような感じ。 | |
>|cs| | |
namespace MefServiceLocatorImpl.Test | |
{ | |
using System.ComponentModel.Composition; | |
using System.ComponentModel.Composition.Hosting; | |
using System.Linq; | |
using System.Reflection; | |
using Microsoft.VisualStudio.TestTools.UnitTesting; | |
using SampleImplementation; | |
[TestClass] | |
public class MefServiceLocatorTest | |
{ | |
private MefServiceLocator locator; | |
[TestInitialize] | |
public void Initialize() | |
{ | |
this.locator = new MefServiceLocator( | |
new AssemblyCatalog(typeof(MefServiceLocatorTest).GetTypeInfo().Assembly)); | |
} | |
[TestCleanup] | |
public void Cleanup() | |
{ | |
this.locator = null; | |
} | |
[TestMethod] | |
public void InitTest() | |
{ | |
Assert.IsNotNull(this.locator); | |
} | |
[TestMethod] | |
public void SingleExportTest() | |
{ | |
var target = locator.GetInstance<ExportTarget>(); | |
Assert.IsNotNull(target); | |
} | |
[TestMethod] | |
public void NamedSingleExportTest() | |
{ | |
var target = locator.GetInstance<NamedExportTarget>("Sample"); | |
Assert.IsNotNull(target); | |
} | |
[TestMethod] | |
[ExpectedException(typeof(CompositionException))] | |
public void NamedSingleExportMissingTest() | |
{ | |
locator.GetInstance<NamedExportTarget>("MissingName"); | |
} | |
[TestMethod] | |
public void ManyExportTest() | |
{ | |
var targets = locator.GetAllInstances<IManyExportTarget>(); | |
Assert.IsNotNull(targets); | |
Assert.AreEqual(targets.Count(), 3); | |
} | |
} | |
[Export] | |
public class ExportTarget | |
{ | |
} | |
[Export("Sample")] | |
public class NamedExportTarget { } | |
public interface IManyExportTarget { } | |
[Export(typeof(IManyExportTarget))] | |
public class ManyExportTarget1 : IManyExportTarget { } | |
[Export(typeof(IManyExportTarget))] | |
public class ManyExportTarget2 : IManyExportTarget { } | |
[Export(typeof(IManyExportTarget))] | |
public class ManyExportTarget3 : IManyExportTarget { } | |
} | |
||< | |
これでオールグリーン!ということでMVVM Light 4のSimpleIoCじゃなくてMEFを使えるようになりそうです。 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment