2012-09-13 20 views
6

मुझे यह प्रश्न व्यक्त करना मुश्किल था (विशेष रूप से शीर्षक रूप में), इसलिए कृपया मेरे साथ भालू।मैं परस्पर निर्भर मॉड्यूल प्रबंधित करने के लिए एमईएफ का उपयोग कैसे कर सकता हूं?

मेरे पास एक ऐसा एप्लिकेशन है जिसे मैं लगातार अलग-अलग चीजों को करने के लिए संशोधित कर रहा हूं। ऐसा लगता है कि एमईएफ कार्यक्षमता के विभिन्न टुकड़ों को प्रबंधित करने का एक अच्छा तरीका हो सकता है। मोटे तौर पर, उस तरह की एक पाइप लाइन के रूप में आवेदन के तीन वर्गों हैं:

  1. अधिग्रहण
  2. परिवर्तन
  3. अभिव्यक्ति

क्या है सरलतम रूप में, मैं इन चरणों में से प्रत्येक व्यक्त कर सकते हैं एक इंटरफ़ेस के रूप में (IAcquisition आदि)। समस्याएं तब शुरू होती हैं जब मैं अधिग्रहण घटकों का उपयोग करना चाहता हूं जो मानक से समृद्ध डेटा प्रदान करते हैं। मैं इस समृद्ध डेटा का उपयोग करने वाले मॉड्यूल को डिज़ाइन करना चाहता हूं, लेकिन मैं वहां पर भरोसा नहीं कर सकता।

मैं निश्चित रूप से इंटरफ़ेस विनिर्देश के सभी डेटा जोड़ सकता हूं। मैं अपवाद फेंककर या शून्य मूल्य लौटकर गरीब डेटा स्रोतों से निपट सकता हूं। यह आदर्श से एक लंबा रास्ता लगता है।

मैं तीन चरणों में एमईएफ बाध्यकारी करना पसंद करूंगा, जैसे मॉड्यूल केवल उपयोगकर्ता को पेश किए जाते हैं यदि वे पहले चुने गए लोगों के साथ संगत हैं।

तो मेरा प्रश्न: क्या मैं मेटाडेटा निर्दिष्ट कर सकता हूं जो उपलब्ध आयात के सेट को प्रतिबंधित करता है?

एक उदाहरण:

Acquision1 BasicData प्रदान करता है केवल

Acquision2

Transformation1 BasicData

Transformation2 की आवश्यकता है BasicData और AdvancedData

Acquisi की आवश्यकता है BasicData और AdvancedData

प्रदान करता है टयन मॉड्यूल पहले चुना जाता है।

यदि अधिग्रहण 1 चुना गया है, तो परिवर्तन 2 की पेशकश न करें, अन्यथा दोनों की पेशकश करें।

क्या यह संभव है? यदि हां, तो कैसे? अब आप अपने अधिग्रहण, परिवर्तन और अभिव्यक्ति घटक

public class BasicData 
{ 
    public string Basic { get; set; } // example data 
} 

public class AdvancedData : BasicData 
{ 
    public string Advanced { get; set; } // example data 
} 

:

उत्तर

4

आपका प्रश्न इस तरह की एक संरचना पता चलता है।आप डेटा के विभिन्न प्रकार से निपटने के लिए सक्षम होना चाहते हैं, तो वे सामान्य कर रहे हैं:

public interface IAcquisition<out TDataKind> 
{ 
    TDataKind Acquire(); 
} 

public interface ITransformation<TDataKind> 
{ 
    TDataKind Transform(TDataKind data); 
} 

public interface IExpression<in TDataKind> 
{ 
    void Express(TDataKind data); 
} 

और अब आप उनमें से बाहर एक पाइपलाइन का निर्माण करने, जो ऐसा दिखता हैं:

IExpression.Express(ITransformation.Transform(IAcquisition.Acquire)); 

तो चलो एक पाइप लाइन बिल्डर का निर्माण शुरू करते हैं:

using System; 
using System.Collections.Generic; 
using System.ComponentModel.Composition; 
using System.ComponentModel.Composition.Hosting; 
using System.ComponentModel.Composition.Primitives; 
using System.Linq; 
using System.Linq.Expressions; 

// namespace ... 

public static class PipelineBuidler 
{ 
    private static readonly string AcquisitionIdentity = 
     AttributedModelServices.GetTypeIdentity(typeof(IAcquisition<>)); 
    private static readonly string TransformationIdentity = 
     AttributedModelServices.GetTypeIdentity(typeof(ITransformation<>)); 
    private static readonly string ExpressionIdentity = 
     AttributedModelServices.GetTypeIdentity(typeof(IExpression<>)); 

    public static Action BuildPipeline(ComposablePartCatalog catalog, 
     Func<IEnumerable<string>, int> acquisitionSelector, 
     Func<IEnumerable<string>, int> transformationSelector, 
     Func<IEnumerable<string>, int> expressionSelector) 
    { 
     var container = new CompositionContainer(catalog); 

वर्ग अपने तीन अनुबंध इंटरफेस के लिए MEF प्रकार पहचान रखती है। हमें सही निर्यात की पहचान करने के लिए बाद में उन लोगों की आवश्यकता होगी। हमारी BuildPipeline विधि Action देता है। यह पाइपलाइन होने जा रहा है, इसलिए हम केवल pipeline() कर सकते हैं। इसमें ComposablePartCatalog और तीन Func एस (निर्यात का चयन करने के लिए) लगता है। इस तरह, हम इस कक्षा के अंदर सभी गंदा काम रख सकते हैं। फिर हम CompositionContainer बनाकर शुरू करते हैं।

 var aImportDef = new ImportDefinition(def => (def.ContractName == AcquisitionIdentity), null, ImportCardinality.ZeroOrMore, true, false); 

यह ImportDefinition बस IAcquisition<> इंटरफेस के सभी निर्यात बाहर फिल्टर:

अब हम ImportDefinition रों, अधिग्रहण घटक के लिए पहले का निर्माण करने के लिए है। अब हम यह कंटेनर से दे सकते हैं:

 var aExports = container.GetExports(aImportDef).ToArray(); 

aExports अब सूची में सभी IAcquisition<> निर्यात रखती है।

 var selectedAExport = aExports[acquisitionSelector(aExports.Select(export => export.Metadata["Name"] as string))]; 

और वहाँ हम अपने अधिग्रहण घटक है: तो चलो इस पर चयनकर्ता चलाते हैं

 var acquisition = selectedAExport.Value; 
     var acquisitionDataKind = (Type)selectedAExport.Metadata["DataKind"]; 

अब हम परिवर्तन और अभिव्यक्ति घटकों के लिए भी ऐसा ही करने जा रहे हैं, लेकिन एक साथ मामूली अंतर: ImportDefinition यह सुनिश्चित करने जा रहा है कि प्रत्येक घटक पिछले घटक के आउटपुट को संभाल सके।

 var tImportDef = new ImportDefinition(def => (def.ContractName == TransformationIdentity) && ((Type)def.Metadata["DataKind"]).IsAssignableFrom(acquisitionDataKind), 
      null, ImportCardinality.ZeroOrMore, true, false); 
     var tExports = container.GetExports(tImportDef).ToArray(); 
     var selectedTExport = tExports[transformationSelector(tExports.Select(export => export.Metadata["Name"] as string))]; 

     var transformation = selectedTExport.Value; 
     var transformationDataKind = (Type)selectedTExport.Metadata["DataKind"]; 

     var eImportDef = new ImportDefinition(def => (def.ContractName == ExpressionIdentity) && ((Type)def.Metadata["DataKind"]).IsAssignableFrom(transformationDataKind), 
      null, ImportCardinality.ZeroOrMore, true, false); 
     var eExports = container.GetExports(eImportDef).ToArray(); 
     var selectedEExport = eExports[expressionSelector(eExports.Select(export => export.Metadata["Name"] as string))]; 

     var expression = selectedEExport.Value; 
     var expressionDataKind = (Type)selectedEExport.Metadata["DataKind"]; 

और अब हम यह सब एक अभिव्यक्ति पेड़ में तार कर सकते हैं:

 var acquired = Expression.Call(Expression.Constant(acquisition), typeof(IAcquisition<>).MakeGenericType(acquisitionDataKind).GetMethod("Acquire")); 
     var transformed = Expression.Call(Expression.Constant(transformation), typeof(ITransformation<>).MakeGenericType(transformationDataKind).GetMethod("Transform"), acquired); 
     var expressed = Expression.Call(Expression.Constant(expression), typeof(IExpression<>).MakeGenericType(expressionDataKind).GetMethod("Express"), transformed); 
     return Expression.Lambda<Action>(expressed).Compile(); 
    } 
} 

और बस हो गया! एक साधारण उदाहरण एप्लिकेशन इस तरह दिखेगा:

[Export(typeof(IAcquisition<>))] 
[ExportMetadata("DataKind", typeof(BasicData))] 
[ExportMetadata("Name", "Basic acquisition")] 
public class Acquisition1 : IAcquisition<BasicData> 
{ 
    public BasicData Acquire() 
    { 
     return new BasicData { Basic = "Acquisition1" }; 
    } 
} 

[Export(typeof(IAcquisition<>))] 
[ExportMetadata("DataKind", typeof(AdvancedData))] 
[ExportMetadata("Name", "Advanced acquisition")] 
public class Acquisition2 : IAcquisition<AdvancedData> 
{ 
    public AdvancedData Acquire() 
    { 
     return new AdvancedData { Advanced = "Acquisition2A", Basic = "Acquisition2B" }; 
    } 
} 

[Export(typeof(ITransformation<>))] 
[ExportMetadata("DataKind", typeof(BasicData))] 
[ExportMetadata("Name", "Basic transformation")] 
public class Transformation1 : ITransformation<BasicData> 
{ 
    public BasicData Transform(BasicData data) 
    { 
     data.Basic += " - Transformed1"; 
     return data; 
    } 
} 

[Export(typeof(ITransformation<>))] 
[ExportMetadata("DataKind", typeof(AdvancedData))] 
[ExportMetadata("Name", "Advanced transformation")] 
public class Transformation2 : ITransformation<AdvancedData> 
{ 
    public AdvancedData Transform(AdvancedData data) 
    { 
     data.Basic += " - Transformed2"; 
     data.Advanced += " - Transformed2"; 
     return data; 
    } 
} 

[Export(typeof(IExpression<>))] 
[ExportMetadata("DataKind", typeof(BasicData))] 
[ExportMetadata("Name", "Basic expression")] 
public class Expression1 : IExpression<BasicData> 
{ 
    public void Express(BasicData data) 
    { 
     Console.WriteLine("Expression1: {0}", data.Basic); 
    } 
} 

[Export(typeof(IExpression<>))] 
[ExportMetadata("DataKind", typeof(AdvancedData))] 
[ExportMetadata("Name", "Advanced expression")] 
public class Expression2 : IExpression<AdvancedData> 
{ 
    public void Express(AdvancedData data) 
    { 
     Console.WriteLine("Expression2: ({0}) - ({1})", data.Basic, data.Advanced); 
    } 
} 


class Program 
{ 
    static void Main(string[] args) 
    { 
     var pipeline = PipelineBuidler.BuildPipeline(new AssemblyCatalog(typeof(Program).Assembly), StringSelector, StringSelector, StringSelector); 
     pipeline(); 
    } 

    static int StringSelector(IEnumerable<string> strings) 
    { 
     int i = 0; 
     foreach (var item in strings) 
      Console.WriteLine("[{0}] {1}", i++, item); 
     return int.Parse(Console.ReadLine()); 
    } 
} 
+0

इस तरह के पूर्ण उत्तर के लिए बहुत धन्यवाद! –