2012-10-24 3 views
0

thesequestions에 설명 된대로 호스트와 다중 작업 처리 클라이언트로 구성된 응용 프로그램을 빌드하려고합니다. 어떤 도움을줌으로써 부분 정의를 발견하고 직렬화하여 실제 런타임 유형을로드하지 않고도 이러한 정의를 저장할 수있는 방법을 알아 냈습니다.MEF를 사용하여 부품을 작성하지만 부품 생성을 연기하십시오.

달성하고자하는 다음 단계 (또는 다음 두 단계는 실제로)는 부품의 실제 생성 및 연결 (부품으로 표시)으로부터 부품 조합을 분할하고 싶습니다.

public sealed class Host 
{ 
    public CreationScript Compose() 
    { 
     CreationScript result; 
     var container = new DelayLoadCompositionContainer(
      s => result = s); 
     container.Compose(); 
     return script; 
    } 

    public static void Main() 
    { 
     var script = Compose(); 

     // Send the script to the client application 
     SendToClient(script); 
    } 
} 

// Lives inside other application 
public sealed class Client 
{ 
    public void Load(CreationScript script) 
    { 
     var container = new ScriptLoader(script); 
     container.Load(); 
    } 

    public static void Main(string scriptText) 
    { 
     var script = new CreationScript(scriptText); 
     Load(script); 
    } 
} 

그래서 그런 식으로 내가 부하 실제로 호스트 응용 프로그램에서 부품을 구성 할 수 있지만 : 나는 부분 집합이있는 경우 그럼 나는 (의사 코드) 다음과 같은 일을 할 수 있도록하고 싶습니다 코드를 작성하여 클라이언트 응용 프로그램에서 실행하십시오. 목표는 모든 지능형 시스템을 한 위치 (호스트)에로드 할 것을 결정하는 것입니다. 실제 작업은 어디에서나 (클라이언트가) 수행 할 수 있습니다.

내가 찾고있는 것은 MEF에서 암시 적으로 생성하는 ComposablePart 그래프를 얻는 방법입니다.

지금 내 질문에 MEF에 이러한 종류의 동작을 구현할 수있는 비트가 있다면? 나는 provider model이 이것으로 나를 도울 수 있다고 의심하지만, 그것은 MEF의 다소 크고 복잡한 부분이므로 모든 지침이 도움이 될 것입니다.

+0

게으른 클래스를 찾고 계십니까? 이 기사의 '지연 인스턴스 생성'섹션을 참조하십시오. http://www.codeproject.com/Articles/376033/From-Zero-to-Proficient-with-MEF – burnttoast11

+0

아니요'게으른 '이 (내가) 찾고있는 것이 아닙니다. 에 대한. 불행히도'Lazy '을 사용하려면'T'를 포함하는 어셈블리가로드되어 있어야합니다. 내가 원하는 것은 플러그인 어셈블리를로드 할 필요없이 파트를 작성하는 방법입니다. 부품의 생성 (즉, 실제 객체 생성)은 다른 시간/장소에서 발생합니다. 플러그인 어셈블리는 생성 시간/장소까지로드되지 않아야합니다. – Petrik

답변

2

많은 조사에서 MEF에서 인스턴스 작성 프로세스와 구성 프로세스를 분리 할 수없는 것 같아서이 문제점에 대한 내 자신의 접근 방식을 만들어야했습니다. 이 솔루션에서는 scanning of plugins이 유형, 가져 오기 및 내보내기 데이터가 어떻게 든 저장되어 있다고 가정합니다.

부품을 작성하려면 각 부품 인스턴스를 추적하고 다른 부품 인스턴스에 연결하는 방법을 기억해야합니다. 이를 수행하는 가장 간단한 방법은 가져 오기가 어떤 내보내기에 연결되어 있는지 추적하는 그래프 데이터 구조를 사용하는 것입니다.

public sealed class CompositionCollection 
{ 
    private readonly Dictionary<PartId, PartDefinition> m_Parts; 
    private readonly Graph<PartId, PartEdge> m_PartConnections; 

    public PartId Add(PartDefinition definition) 
    { 
     var id = new PartId(); 
     m_Parts.Add(id, definition); 
     m_PartConnections.AddVertex(id); 

     return id; 
    } 

    public void Connect(
     PartId importingPart, 
     MyImportDefinition import, 
     PartId exportingPart, 
     MyExportDefinition export) 
    { 
     // Assume that edges point from the export to the import 
     m_PartConnections.AddEdge(
      new PartEdge(
       exportingPart, 
       export, 
       importingPart, 
       import)); 
    } 
} 

두 부분을 연결하기 전에 가져 오기를 내보내기에 연결할 수 있는지 확인해야합니다. 다른 경우에는 MEF가 그렇게하지만이 경우에는 스스로해야합니다. 그 접근하는 방법의 예는 다음과 같습니다 가져 오기 유형이 조금 까다로운 일이 될 수있는 일반적인 유형을 기반으로하는 경우 특별한 경우 (같은 IEnumerable<T>, Lazy<T> 등) 결정을 필요로

public bool Accepts(
    MyImportDefinition importDefinition, 
    MyExportDefinition exportDefinition) 
{ 
    if (!string.Equals(
     importDefinition.ContractName, 
     exportDefinition.ContractName, 
     StringComparison.OrdinalIgnoreCase)) 
    { 
     return false; 
    } 

    // Determine what the actual type is we're importing. MEF provides us with 
    // that information through the RequiredTypeIdentity property. We'll 
    // get the type identity first (e.g. System.String) 
    var importRequiredType = importDefinition.RequiredTypeIdentity; 

    // Once we have the type identity we need to get the type information 
    // (still in serialized format of course) 
    var importRequiredTypeDef = 
     m_Repository.TypeByIdentity(importRequiredType); 

    // Now find the type we're exporting 
    var exportType = ExportedType(exportDefinition); 
    if (AvailableTypeMatchesRequiredType(importRequiredType, exportType)) 
    { 
     return true; 
    } 

    // The import and export can't directly be mapped so maybe the import is a 
    // special case. Try those 
    Func<TypeIdentity, TypeDefinition> toDefinition = 
     t => m_Repository.TypeByIdentity(t); 
    if (ImportIsCollection(importRequiredTypeDef, toDefinition) 
     && ExportMatchesCollectionImport(
      importRequiredType, 
      exportType, 
      toDefinition)) 
    { 
     return true; 
    } 

    if (ImportIsLazy(importRequiredTypeDef, toDefinition) 
     && ExportMatchesLazyImport(importRequiredType, exportType)) 
    { 
     return true; 
    } 

    if (ImportIsFunc(importRequiredTypeDef, toDefinition) 
     && ExportMatchesFuncImport(
      importRequiredType, 
      exportType, 
      exportDefinition)) 
    { 
     return true; 
    } 

    if (ImportIsAction(importRequiredTypeDef, toDefinition) 
     && ExportMatchesActionImport(importRequiredType, exportDefinition)) 
    { 
     return true; 
    } 

    return false; 
} 

하는 것으로.

일단 모든 구성 정보가 저장되면 필요한 모든 정보를 사용할 수 있기 때문에 언제든지 파트의 인스턴스화를 수행 할 수 있습니다. 인스턴스화는 신뢰할 수있는 Activator 클래스의 사용과 함께 반영에 대한 관대 한 도움이 필요하며 독자에게 연습으로 남겨 둡니다.

관련 문제