<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Stefan Henneken</title>
	<atom:link href="http://stefanhenneken.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://stefanhenneken.wordpress.com</link>
	<description>Just another blog about software</description>
	<lastBuildDate>Wed, 30 May 2012 20:16:45 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='stefanhenneken.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Stefan Henneken</title>
		<link>http://stefanhenneken.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://stefanhenneken.wordpress.com/osd.xml" title="Stefan Henneken" />
	<atom:link rel='hub' href='http://stefanhenneken.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Lambda Expressions und Expression Trees &#8211; Teil 1</title>
		<link>http://stefanhenneken.wordpress.com/2012/04/28/lambda-expressions-und-expression-trees-teil-1/</link>
		<comments>http://stefanhenneken.wordpress.com/2012/04/28/lambda-expressions-und-expression-trees-teil-1/#comments</comments>
		<pubDate>Sat, 28 Apr 2012 12:01:00 +0000</pubDate>
		<dc:creator>Stefan Henneken</dc:creator>
				<category><![CDATA[.NET allgemein]]></category>
		<category><![CDATA[Closures]]></category>
		<category><![CDATA[Expression Lambda]]></category>
		<category><![CDATA[Expression Tree]]></category>
		<category><![CDATA[Lambda Expression]]></category>
		<category><![CDATA[Prädikat]]></category>
		<category><![CDATA[Projektion]]></category>
		<category><![CDATA[Statement Lambda]]></category>

		<guid isPermaLink="false">https://stefanhenneken.wordpress.com/?p=362</guid>
		<description><![CDATA[Während Lambda Expressions den meisten Entwicklern vertraut sein sollten, sind Expression Trees eher unbekannt. Expression Trees bieten die Möglichkeit, ausführbaren Code in hierarchischen Datenstrukturen abzubilden. Jeder Knoten wird dabei durch eine Lambda Expression dargestellt. Dieser kann zur Laufzeit geändert werden, wodurch sich interessante Möglichkeiten ergeben. Lambda Expressions sind die Grundlage von Expression Trees. Ein sicherer [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=362&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Während Lambda Expressions den meisten Entwicklern vertraut sein sollten, sind Expression Trees eher unbekannt. Expression Trees bieten die Möglichkeit, ausführbaren Code in hierarchischen Datenstrukturen abzubilden. Jeder Knoten wird dabei durch eine Lambda Expression dargestellt. Dieser kann zur Laufzeit geändert werden, wodurch sich interessante Möglichkeiten ergeben.</p>
<p><span id="more-362"></span>
<p>Lambda Expressions sind die Grundlage von Expression Trees. Ein sicherer Umgang mit Lambda Expressions ist Grundvoraussetzung für das Verständnis von Epression Trees. Deshalb folgt im 1. Teil eine kurze, aber (hoffentlich) vollständige Erläuterung zu Lambda Expressions. Dieser Post ist quasi auch die Essenz aller Beiträge, die ich zu diesem Thema bisher gelesen habe.</p>
<p>Grundsätzlich unterscheidet man zwei Arten von Lambda Expressions. Die <em>Statement Lambdas</em> (Anweisungs Lambdas) und die <em>Expression Lambdas</em> (Ausdrucks Lambdas).</p>
<h1>Statement Lambdas (Anweisungs Lambdas)</h1>
<p>Statement Lambdas kommen immer dort zum Einsatz, wo auch Delegates verwendet werden. Sie sind vergleichbar mit anonymen Methoden, besitzen aber eine kürzere Schreibweise. Hier ein einfaches Beispiel, bei der folgender Delegate vorausgesetzt wird:</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:9c9a3e3e-2604-4dbb-bc43-62648b8a6081" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true;">
public delegate void PrintString(int x, string y);
</pre>
</pre>
</div>
<p>Die Umsetzung als anonyme Methode sieht wie folgt aus:</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:26d9e568-6185-4a18-8223-e96137cecc5c" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
PrintString myDelegate = delegate(int x, string y)
        {
            string s = &quot;Message(&quot; + x + &quot;): &quot; + y;
            Console.WriteLine(s);
        };
myDelegate(100, &quot;Exception&quot;);
</pre>
</pre>
</div>
<p>Das gleiche Beispiel als Statement Lambda:</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:e99d40ec-a1f7-46d7-9fae-ed7081febe8b" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
PrintString myDelegate = (int x, string y) =&gt;
        {
            string s = &quot;Message(&quot; + x + &quot;): &quot; + y;
            Console.WriteLine(s);
        };
myDelegate(100, &quot;Exception&quot;);
</pre>
</pre>
</div>
<p>Das Schlüsselwort <font face="Courier New">delegate</font> entfällt. Stattdessen wird hinter den Eingangsparametern der Operator <font face="Courier New">=&gt;</font> angegeben (gesprochen: &#8216;geht nach&#8217; bzw. &#8216;goes to&#8217;). Danach folgt der Anweisungsblock, in der die eigentliche Logik implementiert wird. </p>
<p>Der Operator <font face="Courier New">=&gt;</font> ist rechtsassoziativ und hat die gleiche Rangfolge wie die Zuweisung (=). Dank Type Inference (Typrückschluss) können die Typangaben bei den Eingangsparametern entfallen:</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:ef297386-6f00-4595-891a-32ad4499c4e2" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
PrintString myDelegate = (x, y) =&gt;
        {
            string s = &quot;Message(&quot; + x + &quot;): &quot; + y;
            Console.WriteLine(s);
        };
myDelegate(100, &quot;Exception&quot;); 
</pre>
</pre>
</div>
<p>Wird nur ein Parameter übergeben, so kann auf die runde Klammer um die Eingangsparameter verzichtet werden:</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:429f5efe-c0bb-4730-9b77-3afddb240c4f" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
public delegate void PrintString(int x);
PrintString myDelegate = x =&gt;
        {
            string s = &quot;Message(&quot; + x + &quot;)&quot;;
            Console.WriteLine(s);
        }; 
</pre>
</pre>
</div>
<p>Bei einer leeren Parameterliste werden jedoch die runden Klammern wieder angegeben:</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:580fa730-9b0b-46cb-91f2-61051a550356" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
public delegate void PrintString();
PrintString myDelegate = () =&gt;
        {
            string s = &quot;Message&quot;;
            Console.WriteLine(s);
        }; 
</pre>
</pre>
</div>
<p>Die Schreibweise der Statement Lambdas ist etwas kompakter als die der anonymen Methoden.</p>
<h1>Expression Lambdas (Ausdrucks Lambdas)</h1>
<p>Ein Expression Lambda ist eine besondere Form der Statement Lambdas. Ein Expression Lambda enthält nur eine Anweisung und liefert immer einen Wert zurück.</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:df90e956-8ee9-4db9-b4f9-1f68286dcaf7" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true;">
public delegate bool IsStringTooLong(int x, string y);

IsStringTooLong myDelegate = (x, y) =&gt; { return y.Length &gt; x; };
bool ret = myDelegate(10, &quot;Message&quot;); 
</pre>
</pre>
</div>
<p>Die gleiche Funktionalität kann durch ein Expression Lambda deutlich einfacher dargestellt werden:</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:012af807-5beb-4dde-aaf4-e3c55da19202" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
IsStringTooLong myDelegate = (x, y) =&gt; y.Length &gt; x;
bool ret = myDelegate(10, &quot;Message&quot;); 
</pre>
</pre>
</div>
<p>Es besteht auch die Möglichkeit statt der Anweisung einen Methodenaufruf anzugeben:</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:db160808-7035-456a-808f-c9401c2e9eaa" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
IsStringTooLong myDelegate = (x, y) =&gt; SomeFunction(x, y);
bool ret = myDelegate(10, &quot;Message&quot;);

static public bool SomeFunction(int x, string y)
{
    return y.Length &gt; x;
} 
</pre>
</pre>
</div>
<p>Expression Lambdas können auch dann angegeben werden, wenn bei einer Methode als Parametertyp <font face="Courier New">Expression&lt;Func&gt;</font> erwartet wird. Ein gutes Beispiel ist das Interface <font face="Courier New">IQueryable</font>.</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:98ebb003-5ae2-42ee-b6d0-3dbfaf949bf7" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
List &lt; string &gt; list = new List &lt; string &gt;() { &quot;Johann&quot;, &quot;Otto&quot;, &quot;Karl&quot; };
IQueryable query = list.AsQueryable();
string a = list.First(x =&gt; { return x.EndsWith(&quot;o&quot;); });
string b = query.First(x =&gt; { return x.EndsWith(&quot;o&quot;); });  // Fehler!!! 
</pre>
</pre>
</div>
<p>Die Methode <font face="Courier New">First()</font> der Klasse <font face="Courier New">List&lt;string&gt;</font> erwartet als Parameter ein Delegate vom Typ <font face="Courier New">Func&lt;string, bool&gt;</font>. Das Interface <font face="Courier New">IQueryable</font> hingegen, erwartet bei der Methode <font face="Courier New">First()</font> den Datentyp <font face="Courier New">Expression&lt;Func&lt;string, bool&gt;&gt;</font>. Aus diesem Grund kann das obige Beispiel nicht compiliert werden.</p>
<p>Wird als Parameter ein Expression Lambda angegeben (also ohne Klammern und ohne <font face="Courier New">return</font>), so lässt sich das Programm übersetzen.</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:994718fe-322d-46cf-bd4d-18ff1f9b3238" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
string c = query.First(x =&gt; x.EndsWith(&quot;s&quot;) );
</pre>
</pre>
</div>
<p>Lambda Expressions lassen sich in zwei Arten aufteilen. Zum einen die Lamda Statements, die Delegates und anonyme Methoden erzeugen und zum anderen die Expression Lambdas, die Instanzen von <font face="Courier New">Expression&lt;&gt;</font> zurückliefern. Expression Lambdas und die Klasse <font face="Courier New">System.Linq.Expressions.Expression</font> finden Anwendung bei den Expression Trees. Dazu später mehr.</p>
<h1>Prädikat</h1>
<p>Liefert ein Lambda Expression einen boolschen Wert zurück, so spricht man auch von einem Prädikat. Die Variable <font face="Courier New">temperatur</font> ist bei dem folgenden Beispiel vom Typ Integer.</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:e765dfe6-976a-485b-80a6-0d32d553a047" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
(temperatur) =&gt; temperatur &gt; 21;
</pre>
</pre>
</div>
<h1>Projektion</h1>
<p>Unterscheidet sich der Datentyp des Rückgabewerts von dem Datentyp des Parameters, so wird dieses als Projektion bezeichnet. Bei dem folgenden Beispiel ist <font face="Courier New">ex</font> vom Datentyp Exception.</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:3fb8fb19-71ab-4c79-9775-0fbc66e442c2" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
(ex) =&gt; ex.Message;
</pre>
</pre>
</div>
<h1>Delegates Action&lt;&gt;(), Func&lt;&gt;() und Predicate&lt;&gt;()</h1>
<p>In den bisherigen Beispielen wurde immer ein eigener Delegate definiert. Das .NET Framework definiert einige hilfreiche Delegates. Hier die drei wichtigsten Varianten, die ich immer wieder gerne einsetze:</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:b36ff445-c8f7-4ab5-ba24-31663d7422d9" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
delegate void Action();
delegate void Action &lt; T1 &gt;(T1 parameter1);
delegate void Action &lt; T1, T2 &gt;(T1 parameter1, T2 parameter2);
delegate void Action &lt; T1, T2, T3 &gt;(T1 parameter1, T2 parameter2, T3 parameter3);
... 

delegate TResult Func &lt; TResult &gt;();
delegate TResult Func &lt; T1, TResult &gt;(T1 parameter1);
delegate TResult Func &lt; T1, T2, TResult &gt;(T1 parameter1, T2 parameter2);
delegate TResult Func &lt; T1, T2, T3, TResult &gt;(T1 parameter1, T2 parameter2, T3 parameter3);
... 

delegate bool Predicate &lt; T1 &gt;(T1 parameter1);
</pre>
</pre>
</div>
<p>Der entscheidende Unterschied bei diesen drei Varianten ist der Rückgabewert. <font face="Courier New">Action&lt;&gt;()</font> gibt immer <font face="Courier New">void</font> zurück, <font face="Courier New">Predicate&lt;&gt;()</font> immer <font face="Courier New">bool</font> und der Rückgabewert bei <font face="Courier New">Func&lt;&gt;()</font> kann frei angegeben werden. Für die Delegates <font face="Courier New">Action&lt;&gt;()</font> und <font face="Courier New">Func&lt;&gt;()</font> gibt es jeweils Überladungen für bis zu 16 Parametern.</p>
<h1>Beispiel für eigene Implementierung</h1>
<p>Das folgende Beispiel fügt der Klasse <font face="Courier New">List</font> die Erweiterungsmethode <font face="Courier New">MyWhere&lt;T&gt;</font> hinzu. Die neue Methode soll sich in etwa so verhalten, wie die sicher schon bekannte Methode <font face="Courier New">Where&lt;T&gt;</font>.</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:10cf314c-2e7a-4fee-b78b-33503660b8c3" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
class Program
{
    static void Main(string[] args)
    {
        new Program().Run();
    }
    void Run()
    {
        List &lt; int &gt; list = new List &lt; int &gt;() { 3, 1, 9, 4, 8, 1, 0, 6, 9 };
        IEnumerable &lt; int &gt; myFilteredList = list.MyWhere &lt; int &gt;(x =&gt; x &lt; 5);
        foreach (var x in myFilteredList)
            Console.WriteLine(x);
    }
}

public static class ExMethods
{
    public static List &lt; T &gt; MyWhere &lt; T &gt;(this List &lt; T &gt; source, Predicate&lt; T &gt; predicate)
    {
        List &lt; T &gt; list = new List &lt; T &gt;();
        foreach (T item in source)
            if (predicate(item))
                list.Add(item);
        return list;
    }
} 
</pre>
</pre>
</div>
<p>In der Erweiterungsmethode wird für jedes Element der Delegate <font face="Courier New">predicate</font> aufgerufen. Über diesen Delegate wird der Teil der Lambda Expression ausgeführt, die sich rechts vom Lambda Operator befinden. In diesem Beispiel: <font face="Courier New">x &lt; 5</font>. Ist die Bedingung erfüllt, so liefert der Delegate <font face="Courier New">True</font> zurück. Dadurch wird in der Erweiterungsmethode das entsprechende Element in eine neue Liste eingefügt, die am Ende der Methode zurückgegeben wird.</p>
<p>Insbesondere LINQ macht von Erweiterungsmethoden und Lambda Expressions reichlich Gebrauch. Die Lesbarkeit der einzelnen Abfragen wird dadurch deutlich erhöht.</p>
<h1>Type Inference (Typrückschluss)</h1>
<p>Bei der Angabe einer Lambda Expression können oftmals die Typangaben bei den Eingangsparametern und bei den Rückgabeparametern (falls vorhanden) entfallen. Der Compiler ermittelt an Hand der Signatur des Delegate die notwendigen Informationen. Dabei sind einige Punkte zu beachten:</p>
<p>Alle Typangaben bei den Eingangsparametern müssen entweder komplett implizit oder explizit angegeben werden:</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:7fc5fb76-e16f-4ebb-97ff-8f94e6ac33bf" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
PrintString myDelegate = (int x, string y) =&gt; { ... };  // ok
PrintString myDelegate = (x, y) =&gt; { ... };             // ok
PrintString myDelegate = (x, string y) =&gt; { ... };      // Fehler
</pre>
</pre>
</div>
<p>- Wird bei den Eingangsparametern kein Datentyp angegeben, so muss dieser implizit in den entsprechenden Datentyp konvertierbar sein.</p>
<p>- Der Rückgabewert (falls vorhanden) muss ebenfalls implizit in den Rückgabewert des Delegates konvertierbar sein.</p>
<p>- Anzahl und Reihenfolge der Eingangsparameter muss mit der Deklaration des Delegates übereinstimmen. Ausnahmen sind optionale und benannte Parameter.</p>
<h1>Optionale und benannte Parameter</h1>
<p>- Bei dem Aufruf des Delegate können die Eingangsparameter per Name angegeben werden. Dadurch ist die Reihenfolge frei wählbar:</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:f50bcb49-0a07-49b7-8d86-7cd2f0cf161e" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
myDelegate(x: 400, y: &quot;Exception&quot;);
myDelegate(y: &quot;Exception&quot;, x: 500); 
</pre>
</pre>
</div>
<p>- Optionale Parameter sind ebenfalls nutzbar. Die Angabe des Standardwerts erfolgt bei der Deklaration des Delegate:</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:6faf9ddd-1130-4e1e-9d7b-81d1f0bdc8e2" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
public delegate void PrintString(int x = 0, string y = &quot;default&quot;);
PrintString myDelegate = (x, y) =&gt; { ... }; 
myDelegate();
myDelegate(200, &quot;Exception&quot;);
myDelegate(300);
</pre>
</pre>
</div>
<p>Weitere Infos zu optionalen und benannten Parametern sind im folgenden Post von mir zu finden: <a href="http://stefanhenneken.wordpress.com/2012/01/05/benannte-und-optionale-parameter">Benannte und optionale Parameter</a></p>
<h1>Closures</h1>
<p>Eine gern benutzte Beschreibung von Closure ist:</p>
<p><em>“Eine Closure verwendet beim Aufruf einen Teil ihres Gültigkeitsbereichs, auch wenn dieser Gültigkeitsbereich außerhalb der Funktion schon nicht mehr existiert.”</em></p>
<p>Alles klar? Ich glaube ein einfaches Beispiel ist hilfreicher:</p>
<div style="margin:0;display:inline;float:none;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:edaf9a40-4f76-47c8-80bb-ca2059ba8d49" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
static void Main(string[] args)
{
    var calculate = GetCalculation();
    var result = calculate(13);
}
public static Func &lt; int, int &gt; GetCalculation()
{
    var value = 99;
    return x =&gt;
            {
                value++;
                return x * value;
            };
} 
</pre>
</pre>
</div>
<p>Über die Methode <font face="Courier New">GetCalculation()</font> wird ein Delegate in Form eines Lambda Statements zurückgegeben. Die Variable <font face="Courier New">value</font> wird als lokale Variable von <font face="Courier New">GetCalculation()</font> mit in den Delegate gegeben. Anschließend wird die Methode verlassen. Man sollte jetzt annehmen, dass die Variable <font face="Courier New">value</font> nicht mehr gültig ist und ihren Wert verliert.</p>
<p>Beim Aufruf der anonymen Methode wird zuerst der Inhalt von <font face="Courier New">value</font> um eins erhöht und dann mit <font face="Courier New">x</font>, in diesem Fall13, multipliziert. Als Ergebnis wird 1300 zurückgegeben. Wie kann das sein?</p>
<p>Beim Verlassen der Methode <font face="Courier New">GetCalculation()</font> wird der Speicherplatz von <font face="Courier New">value</font> nicht wie üblich abgeräumt, weil ja in der anonymen Methode auf ihn verwiesen wird. Der Kontext, in dem <font face="Courier New">value</font> erzeugt wurde, existiert nicht mehr, trotzdem ist die Variable nach wie vor erhalten und steht auch ohne ihren Kontext zur Verfügung. Die Variable <font face="Courier New">value</font> ist an die anonyme Methode gebunden.</p>
<p>Im 2. Teil geht es dann um die Grundlagen von Expression Trees.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/stefanhenneken.wordpress.com/362/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/stefanhenneken.wordpress.com/362/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/stefanhenneken.wordpress.com/362/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/stefanhenneken.wordpress.com/362/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/stefanhenneken.wordpress.com/362/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/stefanhenneken.wordpress.com/362/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/stefanhenneken.wordpress.com/362/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/stefanhenneken.wordpress.com/362/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/stefanhenneken.wordpress.com/362/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/stefanhenneken.wordpress.com/362/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/stefanhenneken.wordpress.com/362/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/stefanhenneken.wordpress.com/362/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/stefanhenneken.wordpress.com/362/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/stefanhenneken.wordpress.com/362/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=362&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://stefanhenneken.wordpress.com/2012/04/28/lambda-expressions-und-expression-trees-teil-1/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/a7a976e45ac7dd401c2765a06bc71cbb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">stefanhenneken</media:title>
		</media:content>
	</item>
		<item>
		<title>MEF Teil 10 &#8211; Parts &#252;ber ExportProvider und App.config in AppDomain laden</title>
		<link>http://stefanhenneken.wordpress.com/2012/03/05/mef-teil-10-parts-ber-exportprovider-und-app-config-in-appdomain-laden/</link>
		<comments>http://stefanhenneken.wordpress.com/2012/03/05/mef-teil-10-parts-ber-exportprovider-und-app-config-in-appdomain-laden/#comments</comments>
		<pubDate>Mon, 05 Mar 2012 20:15:00 +0000</pubDate>
		<dc:creator>Stefan Henneken</dc:creator>
				<category><![CDATA[Managed Extensibility Framework]]></category>
		<category><![CDATA[App.config]]></category>
		<category><![CDATA[ComposablePart]]></category>
		<category><![CDATA[ExportProvider]]></category>
		<category><![CDATA[MEF]]></category>

		<guid isPermaLink="false">https://stefanhenneken.wordpress.com/?p=354</guid>
		<description><![CDATA[Der folgende Post behandelt eigentlich mehrere Themen. Zum einen geht es um das Erstellen eines eigenen ExportProviders, der über die App.config die zu ladenden Parts ausliest. Zum anderen sollen die geladenen Parts in einer eigenen AppDomain ausgeführt werden. Das Managed Extensibility Framework (MEF) nutzt ein attributbasiertes Programmiermodell, um die einzelnen Exports an die Imports zu [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=354&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Der folgende Post behandelt eigentlich mehrere Themen. Zum einen geht es um das Erstellen eines eigenen <font face="Courier New">ExportProviders,</font> der über die <font face="Courier New">App.config</font> die zu ladenden Parts ausliest. Zum anderen sollen die geladenen Parts in einer eigenen <font face="Courier New">AppDomain</font> ausgeführt werden.</p>
<p><span id="more-354"></span>
<p>Das Managed Extensibility Framework (MEF) nutzt ein attributbasiertes Programmiermodell, um die einzelnen Exports an die Imports zu binden. Manchmal kann es aber von Vorteil sein, wenn über eine Konfigurationsdatei die Auswahl der Parts vorgegeben wird. Hierzu bietet sich die <font face="Courier New">App.config</font> an. In einem älteren Post wurde das <a href="http://stefanhenneken.wordpress.com/2010/08/07/erstellen-von-benutzerdefinierten-konfigurationsabschnitten-mit-configurationsection/">Erstellen von benutzerdefinierten Konfigurationsabschnitten in der App.config</a> schon vorgestellt. Der Focus soll mehr auf das Erstellen eines ExportProviders gelegt werden, der die Parts in eine eigene <font face="Courier New">AppDomain</font> lädt und dort mit eingeschränkten Rechten zur Ausführung bringt. Grundlagen zur Erstellung eigener <font face="Courier New">ExportProvider</font> findet ihr <a href="http://stefanhenneken.wordpress.com/2011/11/20/mef-teil-8-eigenen-exportprovider-erstellen/">hier</a>.</p>
<p>Die zu ladenen Parts sind in der <font face="Courier New">App.config</font> aufgelistet:</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:7da936a6-ba87-4339-be2d-e54131aeff2b" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: xml; pad-line-numbers: true; wrap-lines: false;">
&lt;configuration&gt;
  &lt;configSections&gt;
    &lt;section name=&quot;AddInSection&quot; type=&quot;Sample01.AddInConfigurationSection, CarHost&quot;/&gt;
  &lt;/configSections&gt;
  &lt;AddInSection&gt;
    &lt;AddIns&gt;
      &lt;AddIn id=&quot;1&quot; contract=&quot;CarContract.ICarContract&quot;
                    assemblyName=&quot;BMW&quot;
                    typeName=&quot;Sample01.BMW&quot;/&gt;
      &lt;AddIn id=&quot;2&quot; contract=&quot;CarContract.ICarContract&quot;
                    assemblyName=&quot;Mercedes&quot;
                    typeName=&quot;Sample01.Mercedes&quot;/&gt;
    &lt;/AddIns&gt;
  &lt;/AddInSection&gt;
&lt;/configuration&gt;
</pre>
</pre>
</div>
<p>Beide Parts sind identisch aufgebaut und befinden sich jeweils in separaten Assemblies. Wie auch zu erkennen ist, besitzen die Klassen <font face="Courier New">BMW</font> und <font face="Courier New">Mercedes</font> nicht das Attribut <font face="Courier New">Export</font>. Schließlich soll die <font face="Courier New">App.config</font> vorgeben, welche Assemblies zu laden sind, nicht das attributbasierte Programmiermodell von MEF. Da die Assemblies in einer eigenen <font face="Courier New">AppDomain</font> ausgeführt werden sollen und an die Methode Parameter übergeben werden, müssen die Klassen von <font face="Courier New">MarshallByRefObject</font> abgeleitet werden.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:ec1da7fe-327a-452f-a79a-17e7f9b801d8" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
namespace Sample01
{
    public class BMW : MarshalByRefObject, ICarContract
    {
        public void WriteString(string name)
        {
            try
            {
                Console.WriteLine(&quot;BMW: WriteString()&quot;);
                File.WriteAllText(@&quot;C:\Test.txt&quot;, name);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}

namespace Sample01
{
    public class Mercedes : MarshalByRefObject, ICarContract
    {
        public void WriteString(string name)
        {
            try
            {
                Console.WriteLine(&quot;Mercedes: WriteString()&quot;);
                File.WriteAllText(@&quot;C:\Test.txt&quot;, name);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}
</pre>
</pre>
</div>
<p>Die Methode <font face="Courier New">WriteString()</font> soll schreibend auf eine Datei zugreifen. Im Falle einer Exception wird die Fehlermeldung auf die Konsole ausgegeben.</p>
<p>Die Schnittstelle <font face="Courier New">ICarContract</font> liegt ebenfalls in einer separaten Assembly und beinhaltet die gemeinsam genutzte Methode.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:70ed1a48-236c-4b22-b8b6-9f2fd8674c5f" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
namespace CarContract
{
    public interface ICarContract
    {
        void WriteString(string name);
    }
}
</pre>
</pre>
</div>
<p>Die Hauptanwendung ist eher unspektakulär. Es wird eine Instanz des eigenen <font face="Courier New">ExportProviders</font> angelegt. Dieser wird an den Container übergeben. Die Methode <font face="Courier New">ComposeParts()</font> triggert das Laden und Binden der einzelnen Komponenten an. In der <font face="Courier New">Foreach</font>-Schleife wird zum Schluss von jedem Part die enthaltene Methode <font face="Courier New">WriteString()</font> aufgerufen.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:8c7018cb-8747-46e7-afe1-71cddd086005" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
namespace Sample01
{     
    public class Program
    {
        [ImportMany(typeof(ICarContract))]
        private IEnumerable&lt; Lazy&lt; ICarContract &gt; &gt; CarParts { get; set; }
      
        static void Main(string[] args)
        {
            new Program().Run();
        }

        void Run()
        {
            CompositionContainer container = null;

            var provider = new ConfigExportProvider();
            container = new CompositionContainer(provider);
            container.ComposeParts(this);

            foreach (Lazy&lt; ICarContract &gt; carPart in CarParts)
                carPart.Value.WriteString(&quot;Test&quot;);

            container.Dispose();
        }
    }
}
</pre>
</pre>
</div>
<p>Spannend ist die Implementierung des <font face="Courier New">ExportProviders</font>. Im Konstruktor wird der Inhalt der <font face="Courier New">App.config</font> durchlaufen und für jeden Eintrag eine Instanz der Klasse <font face="Courier New">Export</font> angelegt. </p>
<p>Wichtig ist die Methode <font face="Courier New">CreatePart()</font> die im Konstruktor übergeben wird (Zeile 23). Diese erzeugt die einzelnen Parts. Ausgeführt wird <font face="Courier New">CreatePart()</font> sobald MEF die einzelnen Parts benötigt. Da die Imports über die Klasse <font face="Courier New">Lazy&lt;T&gt;</font> gespeichert werden, geschieht dieses bei dem ersten Zugriff auf das Objekt, also bei Aufruf der Methode <font face="Courier New">WriteString()</font>.</p>
<p>Zuvor ruft MEF noch die Methode <font face="Courier New">GetExportsCore()</font> auf. Dort wird die Liste der Exports zurückgegeben, die zu dem Import passen. </p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:b89ec44a-12a4-4be1-8d07-4d5f39dce497" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true; wrap-lines: false;">
namespace Sample01
{
    public class ConfigExportProvider : ExportProvider
    {
        private List&lt; Export &gt; Exports { get; set; }

        public ConfigExportProvider()
        {
            this.Exports = new List&lt; Export &gt;();
            
            AddInConfigurationSection myConfigurationSection =
              (AddInConfigurationSection)ConfigurationManager.GetSection(&quot;AddInSection&quot;);
            foreach (AddInSectionValue sectionValue in myConfigurationSection.SectionValues)
            {
                var metadata = new Dictionary&lt; string, object &gt;();
                metadata.Add(
                        CompositionConstants.ExportTypeIdentityMetadataName,
                        sectionValue.Contract);
                var exportDefinition = new ExportDefinition(sectionValue.Contract, metadata);
                string assemblyName = sectionValue.AssemblyName;
                string typeName = sectionValue.TypeName;
                var export = new Export(exportDefinition,
                                         () =&gt; CreatePart(assemblyName, typeName));
                this.Exports.Add(export);
            }           
        }

        public object CreatePart(string assemblyName, string typeName)
        {
            var info = new AppDomainSetup { 
                   ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase };
            var grantSet = new PermissionSet(PermissionState.None);
            grantSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
            // soll der Dateizugriff erlaubt sein, so muss die folgende Zeile eingefügt werden
            // grantSet.AddPermission(new FileIOPermission(PermissionState.Unrestricted));
            var appDomain = AppDomain.CreateDomain(&quot;AddIn AppDomain&quot;,
                                                    AppDomain.CurrentDomain.Evidence,
                                                    info,
                                                    grantSet);
            var instance = appDomain.CreateInstanceAndUnwrap(assemblyName, typeName); 
            return instance;
        }

        protected override IEnumerable&lt; Export &gt; GetExportsCore(
                                        ImportDefinition definition,
                                        AtomicComposition atomicComposition)
        {          
            return this.Exports.Where(x =&gt; definition.IsConstraintSatisfiedBy(x.Definition));
        }
    }
}
</pre>
</pre>
</div>
<p>In der Methode <font face="Courier New">CreatePart()</font> wird eine separate <font face="Courier New">AppDomain</font> mit stark eingeschränkten Rechten angelegt. In dieser wird die Assembly geladen. Die Rechte sind soweit eingeschränkt, dass Dateizugriffe nicht erlaubt sind. </p>
<p>Wird das Programm ausgeführt, so endet der Versuch, in eine Datei zu schreiben, in einer <font face="Courier New">SecurityException</font>.</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2012/03/commandwindowsample01.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="CommandWindowSample01" border="0" alt="CommandWindowSample01" src="http://stefanhenneken.files.wordpress.com/2012/03/commandwindowsample01_thumb.png?w=517&h=250" width="517" height="250"></a></p>
<p><a href="https://skydrive.live.com/embed?cid=8B31FEFE60F74DF4&amp;resid=8B31FEFE60F74DF4%218120&amp;authkey=AAjzJQ0deTL50_8">Beispiel (Visual Studio 2010)</a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/stefanhenneken.wordpress.com/354/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/stefanhenneken.wordpress.com/354/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/stefanhenneken.wordpress.com/354/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/stefanhenneken.wordpress.com/354/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/stefanhenneken.wordpress.com/354/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/stefanhenneken.wordpress.com/354/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/stefanhenneken.wordpress.com/354/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/stefanhenneken.wordpress.com/354/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/stefanhenneken.wordpress.com/354/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/stefanhenneken.wordpress.com/354/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/stefanhenneken.wordpress.com/354/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/stefanhenneken.wordpress.com/354/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/stefanhenneken.wordpress.com/354/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/stefanhenneken.wordpress.com/354/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=354&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://stefanhenneken.wordpress.com/2012/03/05/mef-teil-10-parts-ber-exportprovider-und-app-config-in-appdomain-laden/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/a7a976e45ac7dd401c2765a06bc71cbb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">stefanhenneken</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2012/03/commandwindowsample01_thumb.png" medium="image">
			<media:title type="html">CommandWindowSample01</media:title>
		</media:content>
	</item>
		<item>
		<title>MEF Teil 9 &#8211; Zugriff auf Composable Parts und Metadaten ohne Lazy&lt;&gt;</title>
		<link>http://stefanhenneken.wordpress.com/2012/02/09/mef-teil-9-zugriff-auf-composable-parts-und-metadaten-ohne-lazy/</link>
		<comments>http://stefanhenneken.wordpress.com/2012/02/09/mef-teil-9-zugriff-auf-composable-parts-und-metadaten-ohne-lazy/#comments</comments>
		<pubDate>Thu, 09 Feb 2012 17:52:00 +0000</pubDate>
		<dc:creator>Stefan Henneken</dc:creator>
				<category><![CDATA[Managed Extensibility Framework]]></category>
		<category><![CDATA[Lazy]]></category>
		<category><![CDATA[MEF]]></category>
		<category><![CDATA[Metadata]]></category>

		<guid isPermaLink="false">https://stefanhenneken.wordpress.com/?p=349</guid>
		<description><![CDATA[Der Zugriff auf Metadaten erfolgt über die Klasse Lazy&#60;T, TMetadata&#62;. So steht es in der Dokumentation zum Managed Extensibility Framework (MEF). Doch es geht auch ohne Lazy&#60;T, TMetadata&#62;. Was dabei zu beachten ist und welche Möglichkeiten sich dadurch ergeben, zeigt das folgende Beispiel. Metadaten werden mit Hilfe des Attributes ExportMetadata bekannt gegeben. Dazu wird jedes [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=349&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Der Zugriff auf Metadaten erfolgt über die Klasse <font face="Courier New">Lazy&lt;T, TMetadata&gt;</font>. So steht es in der Dokumentation zum Managed Extensibility Framework (MEF). Doch es geht auch ohne <font face="Courier New">Lazy&lt;T, TMetadata&gt;</font>. Was dabei zu beachten ist und welche Möglichkeiten sich dadurch ergeben, zeigt das folgende Beispiel.</p>
<p><span id="more-349"></span>
<p>Metadaten werden mit Hilfe des Attributes <font face="Courier New">ExportMetadata</font> bekannt gegeben. Dazu wird jedes Element der Metadaten durch ein Name-Werte-Paar beschrieben. Der Name ist immer vom Typ <font face="Courier New">String</font>, während der Wert vom Typ <font face="Courier New">Object</font> ist. Wie der Zugriff auf Metadaten i.d.R. erfolgt, wird im Artikel <a href="http://stefanhenneken.wordpress.com/2011/06/05/mef-teil-2-metadaten-und-erstellungsrichtlinien">MEF Teil 2 – Metadaten und Erstellungsrichtlinien</a> beschrieben.</p>
<p>Im Folgenden Beispiel sind die Parts wie folgt implementiert:</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:32062a61-7cfa-4dfd-a37a-887d9a30b51e" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true; wrap-lines: false;">
[ExportMetadata(&quot;Name&quot;, &quot;Mercedes&quot;)]
[ExportMetadata(&quot;Price&quot;, (uint)48000)]
[Export(typeof(ICarContract))]
public class Mercedes : ICarContract
{
    private static int counter;
    public Mercedes()
    {
        Console.WriteLine(&quot;constructor Mercedes: {0}&quot;, ++counter);
    }
    public string GetName()
    {
        return &quot;Mercedes&quot;;
    }
}
</pre>
</pre>
</div>
<p>Die Schnittstelle <font face="Courier New">ICarContract</font> dient ebenfalls zur Definition des Contracts:</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:4ed21caf-6de1-4a01-9071-bded61096c77" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
public interface ICarContract
{
    string GetName();
}
</pre>
</pre>
</div>
<p>Das Auslesen der Metadaten kann jetzt recht einfach über den Container erfolgen. </p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:058bf4d4-7543-4529-b20b-ee31ce697b14" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: css; wrap-lines: false;">
class Program
{
    [ImportMany(typeof(ICarContract))]
    private List&lt; ICarContract &gt; CarParts = new List&lt; ICarContract &gt;();

    static void Main(string[] args)
    {
        new Program().Run();
    }

    void Run()
    {
        var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()); 
        var container = new CompositionContainer(catalog); 
        container.ComposeParts(this);

        foreach (ComposablePartDefinition partDefinition in container.Catalog.Parts)
        {
            foreach (ExportDefinition exportDefinition in partDefinition.ExportDefinitions)
            {
                Console.WriteLine(&quot;Metadaten:&quot;);
                IDictionary&lt; String, Object &gt; metadata = exportDefinition.Metadata;
                Console.WriteLine(&quot;Name: {0}&quot;, metadata[&quot;Name&quot;].ToString());
                Console.WriteLine(&quot;Price: {0}\n&quot;, metadata[&quot;Price&quot;].ToString());
            }
        }
        container.Dispose();
    }
}
</pre>
</pre>
</div>
<p>Wer sich über die Bedeutung der einzelnen Klassen noch nicht ganz im Klaren ist, wird vielleicht hier fündig: <a href="http://stefanhenneken.wordpress.com/2011/11/20/mef-teil-8-eigenen-exportprovider-erstellen">MEF Teil 8 – Eigenen ExportProvider erstellen</a>.</p>
<p>Das obige Beispiel hat nur einen großen Haken. Mir ist es nicht gelungen, die Metadaten den einzelnen Objekten aus der Liste <font face="Courier New">CarParts</font> zuzuordnen. Was nützen die Metadaten, wenn diese dem Export nicht zugeordnet werden können?</p>
<p>Um dieses Problem zu lösen, musste ich das Programm so abändern, dass das Erzeugen der einzelnen Car-Objekte nicht von MEF ausgeführt wird, sondern ‘von Hand’.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:b1d672be-79b0-48e3-b70f-eb11734d18d0" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
class Program
{
    // [ImportMany(typeof(ICarContract))]
    private List&lt; ICarContract &gt; CarParts = new List&lt; ICarContract &gt;();

    static void Main(string[] args)
    {
        new Program().Run();
    }

    void Run()
    {
        var catalog = new AssemblyCatalog(System.Reflection.Assembly.GetExecutingAssembly()); 
        var container = new CompositionContainer(catalog); 
        // container.ComposeParts(this);

        foreach (ComposablePartDefinition partDefinition in container.Catalog.Parts)
        {
            ComposablePart part = partDefinition.CreatePart();               
            foreach (ExportDefinition exportDefinition in partDefinition.ExportDefinitions)
            {
                Console.WriteLine(&quot;Create new instance&quot;);
                ICarContract car = (ICarContract)part.GetExportedValue(exportDefinition);
                Console.WriteLine(&quot;Metadaten:&quot;);
                IDictionary&lt; String, Object &gt; metadata = exportDefinition.Metadata;
                Console.WriteLine(&quot;Name: {0}&quot;, metadata[&quot;Name&quot;].ToString());
                Console.WriteLine(&quot;Price: {0}\n&quot;, metadata[&quot;Price&quot;].ToString());
                CarParts.Add(car);
            }
        }

        Console.WriteLine(&quot;\nCarParts:&quot;);
        foreach (ICarContract carParts in CarParts)
            Console.WriteLine(carParts.GetName());

        container.Dispose();
    }
}
</pre>
</pre>
</div>
<p>Da die Objekte selber erzeugt werden, kann auf das Attribut <font face="Courier New">Import</font> in Zeile 3 verzichtet werden. Ebenfalls nicht mehr notwendig ist der Aufruf der Methode <font face="Courier New">ComposeParts()</font> in Zeile 15. Der Aufruf würde so oder so nichts bewirken, da es im Programm keinen passenden Import mehr gibt. Ohne Import gibt es nichts zu composen.</p>
<p>Das Erzeugen der Car-Objekte erfolgt mit Hilfe der Methode <font face="Courier New">GetExportValue()</font> der Klasse <font face="Courier New">ComposablePart</font>. In Zeile 19 wird das notwendige Objekt erzeugt und in Zeile 23 das gewünschte Car-Objekt instanziiert. Die dann folgenden Metadaten gehören somit zwangsläufig zu dem zuvor erzeugten Objekt. Damit unsere Liste <font face="Courier New">CarParts</font> nicht leer bleibt, wird in Zeile 28 das Objekt der Liste hinzugefügt.</p>
<p>Auch wenn das manuelle Anlegen der Objekte einen der größten Vorteile von MEF untergräbt, so ergeben sich doch einige neue Möglichkeiten. Die Metadaten könnten z.B. direkt ausgewertet werden, um so die erzeugten Objekte unterschiedlichen Listen zuzuordnen.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:597c2251-5f8a-4583-a9fe-d420fdc37d54" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true; wrap-lines: false;">
if ((uint)metadata[&quot;Price&quot;] &gt; 50000)
    ExpensiveCarParts.Add(car);
else
    CarParts.Add(car);
</pre>
</pre>
</div>
<p><strong>Fazit:</strong></p>
<p>So richtig kommt bei diesem Ansatz keine Freude auf. Die Nachteile überwiegen klar die Vorteile. Das Angenehme bei MEF ist eben das automatische Composen, also das Zuordnen der Exports zu den Imports. Auch ist der typsichere Zugriff auf die Metadaten nicht mehr möglich. Sollen die Exports an Hand der Metadaten gefiltert oder sortiert werden, so bietet&nbsp; <font face="Courier New">Lazy&lt;T, TMetadata&gt;</font> deutlich mehr Komfort. Ein Beispiel mit LINQ ist in <a href="http://stefanhenneken.wordpress.com/2011/06/05/mef-teil-2-metadaten-und-erstellungsrichtlinien">MEF Teil 2 – Metadaten und Erstellungsrichtlinien</a> zu finden.</p>
<p><a href="https://skydrive.live.com/embed?cid=8B31FEFE60F74DF4&amp;resid=8B31FEFE60F74DF4%21187&amp;authkey=ABkxYt7xq0Iv_bo">Beispiel (Visual Studio 2010)</a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/stefanhenneken.wordpress.com/349/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/stefanhenneken.wordpress.com/349/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/stefanhenneken.wordpress.com/349/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/stefanhenneken.wordpress.com/349/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/stefanhenneken.wordpress.com/349/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/stefanhenneken.wordpress.com/349/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/stefanhenneken.wordpress.com/349/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/stefanhenneken.wordpress.com/349/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/stefanhenneken.wordpress.com/349/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/stefanhenneken.wordpress.com/349/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/stefanhenneken.wordpress.com/349/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/stefanhenneken.wordpress.com/349/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/stefanhenneken.wordpress.com/349/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/stefanhenneken.wordpress.com/349/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=349&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://stefanhenneken.wordpress.com/2012/02/09/mef-teil-9-zugriff-auf-composable-parts-und-metadaten-ohne-lazy/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/a7a976e45ac7dd401c2765a06bc71cbb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">stefanhenneken</media:title>
		</media:content>
	</item>
		<item>
		<title>Benannte und optionale Parameter</title>
		<link>http://stefanhenneken.wordpress.com/2012/01/05/benannte-und-optionale-parameter/</link>
		<comments>http://stefanhenneken.wordpress.com/2012/01/05/benannte-und-optionale-parameter/#comments</comments>
		<pubDate>Thu, 05 Jan 2012 20:51:00 +0000</pubDate>
		<dc:creator>Stefan Henneken</dc:creator>
				<category><![CDATA[.NET allgemein]]></category>
		<category><![CDATA[DefaultParameterValueAttribute]]></category>
		<category><![CDATA[OptionalAttribute]]></category>

		<guid isPermaLink="false">https://stefanhenneken.wordpress.com/?p=341</guid>
		<description><![CDATA[Manchmal stolpert man bei C# über Leistungsmerkmale, von denen man sich wünscht, schon eher davon gehört zu haben. Ein gutes Beispiel hierfür sind benannte und optionale Parameter, die seit C# 4.0 bereitgestellt werden. Doch es lauern auch Gefahren, die man kennen sollte. Optionale und benannte Parameter werden sehr häufig zusammen erwähnt, sind aber zwei verschiedene [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=341&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Manchmal stolpert man bei C# über Leistungsmerkmale, von denen man sich wünscht, schon eher davon gehört zu haben. Ein gutes Beispiel hierfür sind benannte und optionale Parameter, die seit C# 4.0 bereitgestellt werden. Doch es lauern auch Gefahren, die man kennen sollte.</p>
<p><span id="more-341"></span>
<p>Optionale und benannte Parameter werden sehr häufig zusammen erwähnt, sind aber zwei verschiedene Leistungsmerkmale. Optionale Parameter sind, wie der Name schon sagt, optional. Diese können bei einem Methodenaufruf weggelassen werden. Durch benannte Parameter ist die Reihenfolge der Parameter bei einem Methodenaufruf beliebig.</p>
<p>Beide Techniken lassen sich auf Methoden, Konstruktoren und Indexer anwenden.</p>
<h1>Optionale Parameter</h1>
<p>Um dem Nutzer einer Klasse den maximalen Komfort zu bieten, werden Methoden mit vielen Parametern sehr häufig überladen. Somit steht die gleiche Methode in unterschiedlichen Varianten zur Verfügung. Ein recht gutes Beispiel ist die statische Methode <font face="Courier New">Show()</font> der Klasse <font face="Courier New">MessageBox</font>:</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:34c195df-0607-40c0-b563-39976f41bb00" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true; wrap-lines: false;">
public class MessageBox
{
    public static DialogResult Show(string text);
    public static DialogResult Show(string text, string caption);
    public static DialogResult Show(string text, string caption, MessageBoxButtons buttons);
    public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon);
    public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton);
    public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options);
    public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, bool displayHelpButton);
    public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath);
    public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, HelpNavigator navigator);
    public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, string keyword);
    public static DialogResult Show(string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, HelpNavigator navigator, object param);

    public static DialogResult Show(IWin32Window owner, string text);
    public static DialogResult Show(IWin32Window owner, string text, string caption);
    public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons);
    public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon);
    public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton);
    public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options);
    public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath);
    public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, HelpNavigator navigator);
    public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, string keyword);
    public static DialogResult Show(IWin32Window owner, string text, string caption, MessageBoxButtons buttons, MessageBoxIcon icon, MessageBoxDefaultButton defaultButton, MessageBoxOptions options, string helpFilePath, HelpNavigator navigator, object param);
}
</pre>
</pre>
</div>
<p>Seit C# 4.0 kann bei der Definition einer Methode angegeben werden, ob ein Parameter beim Aufruf erforderlich ist oder nicht. Hierzu wird hinter den gewünschten Parametern ein Standardwert angegeben. Der Standardwert muss immer eine Konstante sein. Wird bei dem Methodenaufruf kein Wert an den Parameter übergeben, so wird der Standardwert verwendet. Optionale Parameter müssen immer am Ende der Parameterliste, nach allen obligatorischen Parametern, stehen.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:d57d3dfd-2e84-45db-be2d-d5096fb2c192" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
public void TestMethod(int x, int y = 123, int z = 456)
{
    Console.WriteLine(&quot;x: {0}  y: {1}  z: {2}&quot;, x, y, z);
}
</pre>
</pre>
</div>
<p>Die Methode lässt sich auf verschiedene Arten aufrufen. Allerdings dürfen optionale Parametern bei dem Aufruf nicht ‘übersprungen’ werden.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:7273f694-46f3-4b24-99a9-7592c760528f" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
TestMethod(1);
TestMethod(1, 2);
TestMethod(1, 2, 3);
TestMethod(1, , 3);  // Fehler
</pre>
</pre>
</div>
<p>Es ist möglich, Methoden zu überladen, die optionale Parameter besitzen.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:1f9e079c-5afd-4133-b9e1-f12944a22f2a" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
public void TestMethod(int x, int y = 123, int z = 456)
{
    Console.WriteLine(&quot;x: {0}  y: {1}  z: {2}&quot;, x, y, z);
}
public void TestMethod(int x)
{
    Console.WriteLine(&quot;x: {0}&quot;, x);
}

TestMethod(1);
</pre>
</pre>
</div>
<p>Die Verwendung von <font face="Courier New">TestMethod(1)</font> hat zur Folge, dass die Methode <font face="Courier New">TestMethod(int x)</font> aufgerufen wird. Es wird also die Methode bevorzugt, die keine optionalen Parameter hat.</p>
<p>Da der Standardwert immer eine Konstante sein muss, gibt der Compiler bei folgendem Beispiel einen Fehler aus: </p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:19a3759f-d6de-445d-90b7-05cd075db807" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
// nicht erlaubt
public void TestMethod(int x, int y = 123, Foo z = new Foo())
{
    Console.WriteLine(&quot;x: {0}  y: {1}  z: {2}&quot;, x, y, z);
}
</pre>
</pre>
</div>
<p>Anders sieht das bei Enums und Strukturen aus. Da dieses Wertetypen sind, kann der <font face="Courier New">new</font>-Operator benutzt werden. allerdings nur in Verbindung mit dem Standardkonstruktor.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:868fac2f-f369-47d1-8de0-2726e52f56e2" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
public void TestMethod(int x, int y = 123, StructFoo z = new StructFoo())
{
    Console.WriteLine(&quot;x: {0}  y: {1}  z: {2}&quot;, x, y, z);
}
</pre>
</pre>
</div>
<p>Das Schlüsselwort <font face="Courier New">default(T)</font> kann ebenfalls benutzt werden:</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:8d5de4b9-7435-499f-ac64-5a5f313995b6" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
public void TestMethod(int x, int y = 123, Foo z = default(Foo))
{
    Console.WriteLine(&quot;x: {0}  y: {1}  z: {2}&quot;, x, y, z);
}
</pre>
</pre>
</div>
<p>Die Variable <font face="Courier New">z</font> erhält den Wert <font face="Courier New">null</font>, wenn beim Aufruf kein Wert angegeben wurde.</p>
<p>IntelliSense zeigt optionale Parameter in eckigen Klammern an:</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2012/01/picture01.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Picture01" border="0" alt="Picture01" src="http://stefanhenneken.files.wordpress.com/2012/01/picture01_thumb.png?w=328&h=43" width="328" height="43"></a></p>
<h3>Die Attribute Optional und DefaultParameterValue</h3>
<p>Das Attribute <font face="Courier New">Optional</font> kann ebenfalls benutzt werden, um einen Parameter als optional zu kennzeichnen. Wird bei dem Aufruf der Methode dem Parameter kein Wert zugewiesen, so wird der Standardwert des jeweiligen Datentyps benutzt. </p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:cee48063-a0be-4353-a293-9f1a637e2e47" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
public void TestMethod(int x, [Optional]int y, [Optional]int z)
{
    Console.WriteLine(&quot;x: {0}  y: {1}  z: {2}&quot;, x, y, z);
}
</pre>
</pre>
</div>
<p>Ergänzt werden kann das Attribut <font face="Courier New">Optional</font> durch das Attribut <font face="Courier New">DefaultParameterValue</font>.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:662ea3ed-95c5-46eb-bc85-30cd2c3d3d7b" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; toolbar: true; wrap-lines: false;">
public void TestMethod(int x, [Optional, DefaultParameterValue(123)]int y,
                              [Optional, DefaultParameterValue(456)]int z)
{
    Console.WriteLine(&quot;x: {0}  y: {1}  z: {2}&quot;, x, y, z);
}
</pre>
</pre>
</div>
<p>Somit ist die Kombination aus beiden Attributen gleichzusetzen mit den obigen Beispielen. Es gelten auch die gleichen Randbedingungen.</p>
<h3>Gefahrenquelle</h3>
<p>Besondere Vorsicht ist geboten, wenn die Methode und der Aufrufer der Methode in unterschiedlichen Projekten abgelegt sind. Das folgende Beispiel enthält zwei Klassen in getrennten Assemblies.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:b4dd8f12-350f-46ca-95f7-02d35fd9bc4b" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true; wrap-lines: false;">
class Program
{
    static void Main(string[] args)
    {
        new Program().Run();
    }
    public void Run()
    {
        ExternalClass externalClass = new ExternalClass();
        externalClass.TestMethod(1);
        externalClass.TestMethod(1, 2);
        externalClass.TestMethod(1, 2, 3);
    }
}

class ExternalClass
{
    public void TestMethod(int x, int y = 123, int z = 456)
    {
        Console.WriteLine(&quot;x: {0}  y: {1}  z: {2}&quot;, x, y, z);
    }
}
</pre>
</pre>
</div>
<p>Was zu beachten ist, wird deutlich bei der Analyse des IL-Codes vom Aufrufer. Der Compiler kopiert die Werte in die Methodenaufrufe.</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2012/01/picture02.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Picture02" border="0" alt="Picture02" src="http://stefanhenneken.files.wordpress.com/2012/01/picture02_thumb.png?w=591&h=347" width="591" height="347"></a></p>
<p>Das kann sehr unangenehm werden, wenn bei der Methode <font face="Courier New">TestMethod()</font> die Standardwerte geändert werden, der Aufrufer aber nicht neu compiliert wird. Die Methode wird weiterhin mit den alten Standardwerten aufgerufen.</p>
<p>Meiner Meinung nach sollten optionale Parameter (mit Standardwert) nur innerhalb einer Assembly angewendet werden. Gegen das Attribut <font face="Courier New">Optional</font> (ohne Standardwert) ist nichts einzuwenden, da das oben gezeigte Problem nicht auftreten kann.</p>
<h1>Benannte Parameter</h1>
<p>Benannte Parameter können bei jedem Methodenaufruf verwendet werden. Hierbei wird vor dem Wert auch der Name des Parameters angegeben. Dadurch können die Parameter in beliebiger Reihenfolge angegeben werden. Als Beispiel soll folgende Methode dienen:</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:7f46cd6c-f5cf-46b8-afe4-020be1cbc071" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
public void TestMethod(int xPosition, int yPosition, int size)
{
    Console.WriteLine(&quot;x: {0}  y: {1}  z: {2}&quot;, xPosition, yPosition, size);
}
</pre>
</pre>
</div>
<p>Folgende Aufrufe sind u.a. möglich:</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:dde2fcc3-4399-4f11-8922-aae4e8e46173" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
TestMethod(1, 2, 3);
TestMethod(xPosition: 1, yPosition: 2, size: 3);
TestMethod(size: 3, yPosition: 2, xPosition: 1);
</pre>
</pre>
</div>
<p>Der Compiler sorgt dafür, dass die Methode immer vollständig mit allen Parametern aufgerufen wird.</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2012/01/picture03.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Picture03" border="0" alt="Picture03" src="http://stefanhenneken.files.wordpress.com/2012/01/picture03_thumb.png?w=545&h=351" width="545" height="351"></a></p>
<p>Benannte Parameter müssen immer am Ende des Methodenaufrufs stehen.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:f4f0c59c-0bff-4443-9285-441e405ae830" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
TestMethod(1, yPosition: 2, size: 3);
TestMethod(yPosition: 2, xPosition: 1, 3);  // Fehler
TestMethod(xPosition: 1, 3, size: 3);       // Fehler
</pre>
</pre>
</div>
<p>Neben der Tatsache, dass die Reihenfolge geändert werden kann, erhöht sich auch die Lesbarkeit des Quellcodes. Allerdings nur dann, wenn die Parameter einer Methode auch aussagekräftige Namen haben.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:63ab52fb-3701-429d-b5b3-238b86d597e9" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
TestMethod(1, 2, 3);

TestMethod(xPosition: 1, yPosition: 2, size: 3);  // lesbarer

</pre>
</pre>
</div>
<h3>Gefahrenquelle</h3>
<p>Die Auswertung der Parameter geschieht in der gleichen Reihenfolge, in der sie auch genannt werden.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:8669c8c9-44f0-4426-ab3d-2b7f68ea540b" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
int position = 1;
TestMethod(yPosition: position++, xPosition: position, size: 3);
</pre>
</pre>
</div>
<p>Der Aufruf liefert für <font face="Courier New">xPosition</font> den Wert 2 und für <font face="Courier New">yPosition</font> den Wert 1.</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2012/01/picture04.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="Picture04" border="0" alt="Picture04" src="http://stefanhenneken.files.wordpress.com/2012/01/picture04_thumb.png?w=549&h=300" width="549" height="300"></a></p>
<p>Der IL-Code zeigt sehr deutlich, wie die Parameter in der Reihenfolge, in der sie genannt werden, auch ausgewertet werden.</p>
<p>Liegen Methode und Aufrufer in unterschiedlichen Assemblies, so kann durchaus der Name eines Parameters geändert werden, ohne dass der Aufrufer neu compiliert werden muss. Das liegt ganz einfach daran, dass der Name der Variablen im IL-Code nicht mehr auftaucht. Probleme treten erst dann auf, wenn der Aufrufer neu compiliert wird.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/stefanhenneken.wordpress.com/341/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/stefanhenneken.wordpress.com/341/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/stefanhenneken.wordpress.com/341/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/stefanhenneken.wordpress.com/341/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/stefanhenneken.wordpress.com/341/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/stefanhenneken.wordpress.com/341/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/stefanhenneken.wordpress.com/341/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/stefanhenneken.wordpress.com/341/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/stefanhenneken.wordpress.com/341/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/stefanhenneken.wordpress.com/341/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/stefanhenneken.wordpress.com/341/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/stefanhenneken.wordpress.com/341/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/stefanhenneken.wordpress.com/341/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/stefanhenneken.wordpress.com/341/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=341&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://stefanhenneken.wordpress.com/2012/01/05/benannte-und-optionale-parameter/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/a7a976e45ac7dd401c2765a06bc71cbb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">stefanhenneken</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2012/01/picture01_thumb.png" medium="image">
			<media:title type="html">Picture01</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2012/01/picture02_thumb.png" medium="image">
			<media:title type="html">Picture02</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2012/01/picture03_thumb.png" medium="image">
			<media:title type="html">Picture03</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2012/01/picture04_thumb.png" medium="image">
			<media:title type="html">Picture04</media:title>
		</media:content>
	</item>
		<item>
		<title>Einsatz von Lazy&lt;T, TMetadata&gt; ohne MEF</title>
		<link>http://stefanhenneken.wordpress.com/2011/12/06/einsatz-von-lazyt-tmetadata-ohne-mef/</link>
		<comments>http://stefanhenneken.wordpress.com/2011/12/06/einsatz-von-lazyt-tmetadata-ohne-mef/#comments</comments>
		<pubDate>Tue, 06 Dec 2011 20:11:00 +0000</pubDate>
		<dc:creator>Stefan Henneken</dc:creator>
				<category><![CDATA[.NET allgemein]]></category>
		<category><![CDATA[Lazy]]></category>

		<guid isPermaLink="false">https://stefanhenneken.wordpress.com/?p=328</guid>
		<description><![CDATA[Im Zusammenhang mit dem Managed Extensibility Framework (MEF) sind mir zum ersten mal die Klassen Lazy&#60;T&#62; und Lazy&#60;T, TMetadata&#62; über den Weg gelaufen. Während Lazy&#60;T&#62; ausreichend beschrieben wird, so ist Lazy&#60;T, TMetadata&#62; immer nur in Zusammenhang mit MEF zu finden. Dabei kann Lazy&#60;T, TMetadata&#62; auch ohne MEF sinnvoll eingesetzt werden. Wie Lazy&#60;T&#62; und Lazy&#60;T, TMetadata&#62; [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=328&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Im Zusammenhang mit dem Managed Extensibility Framework (MEF) sind mir zum ersten mal die Klassen <font face="Courier New">Lazy&lt;T&gt;</font> und <font face="Courier New">Lazy&lt;T, TMetadata&gt;</font> über den Weg gelaufen. Während <font face="Courier New">Lazy&lt;T&gt;</font> ausreichend beschrieben wird, so ist <font face="Courier New">Lazy&lt;T, TMetadata&gt;</font> immer nur in Zusammenhang mit MEF zu finden. Dabei kann <font face="Courier New">Lazy&lt;T, TMetadata&gt;</font> auch ohne MEF sinnvoll eingesetzt werden.</p>
<p><span id="more-328"></span>
<p>Wie <font face="Courier New">Lazy&lt;T&gt;</font> und <font face="Courier New">Lazy&lt;T, TMetadata&gt;</font> in Zusammenhang mit MEF eingesetzt werden, habe ich schon ausreichend in <a href="http://stefanhenneken.wordpress.com/2011/05/22/mef-teil-1-grundlagen-imports-und-exports/">MEF Teil 1 – Grundlagen, Imports und Exports</a> und <a href="http://stefanhenneken.wordpress.com/2011/06/05/mef-teil-2-metadaten-und-erstellungsrichtlinien/">MEF Teil 2 – Metadaten und Erstellungsrichtlinien</a> beschrieben. Wer wissen will, wie die Klasse <font face="Courier New">Lazy&lt;T&gt;</font> ohne MEF sinnvoll benutzt werden kann, dem sei der Blog von <a href="http://www.just-about.net/lazy-t-deutsch">Hendrik Lösch</a> empfohlen. Hilfreich ist auch der Artikel <a href="http://msdn.microsoft.com/de-de/library/dd997286.aspx">Lazy Initialization</a> aus dem MSDN. Doch wie kann die Klasse <font face="Courier New">Lazy&lt;T, TMetadata&gt;</font> ohne MEF verwendet werden? </p>
<p>Während <font face="Courier New">Lazy&lt;T&gt;</font> direkt in <font face="Courier New">mscorlib.dll</font> enthalten ist, wurde <font face="Courier New">Lazy&lt;T, TMetadata&gt;</font> in <font face="Courier New">System.ComponentModel.Composition.dll</font> ‘versteckt’. Dementsprechend muss die Referenz auf die DLL dem Projekt hinzugefügt werden.</p>
<p>Im Klassendiagramm ist zu erkennen, dass die Klasse <font face="Courier New">Lazy&lt;T, TMetadata&gt;</font> von <font face="Courier New">Lazy&lt;T&gt;</font> abgeleitet wurde. Neben der Eigenschaft <font face="Courier New">Metadata</font> gibt es noch zusätzliche Konstruktoren, mit denen die Metadaten initialisiert werden. </p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/12/classdiagram.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ClassDiagram" border="0" alt="ClassDiagram" src="http://stefanhenneken.files.wordpress.com/2011/12/classdiagram_thumb.png?w=571&h=681" width="571" height="681"></a></p>
<h1>Beispiel</h1>
<p>Als Beispiel soll ein Logger dienen, der den Text in verschiedenen Formaten ausgeben kann. Hierzu werden zwei Klassen angelegt, die beide die gleiche Schnittstelle implementieren. Beide Klassen geben über die Methode <font face="Courier New">WriteMessage()</font> einen Text in unterschiedlichen Formaten aus.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:dad4662c-5923-4e5a-b8c6-82ea1d83d7aa" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true; wrap-lines: false;">
public interface ILoggerClass
{
    void WriteMessage(string message);
}

public class LongFormatLogger : ILoggerClass
{
    public LongFormatLogger()
    {
        Console.WriteLine(&quot;LongFormatLogger constructor&quot;);
    }
    public void WriteMessage(string message)
    {
        Console.WriteLine(&quot;Message (&quot; +
                          DateTime.Now.ToLongDateString() +
                          &quot;): &quot; +
                          message);
    }
}

public class ShortFormatLogger : ILoggerClass
{
    public ShortFormatLogger()
    {
        Console.WriteLine(&quot;ShortFormatLogger constructor&quot;);
    }
    public void WriteMessage(string message)
    {
        Console.WriteLine(&quot;Message (&quot; +
                          DateTime.Now.ToShortDateString() +
                          &quot;): &quot; +
                          message);
    }
}
</pre>
</pre>
</div>
<p>So weit so gut. Jetzt benötigen wir noch die Klasse für die Metadaten.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:7c8ab3b3-6599-4f42-aa40-b405d52b6d42" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
public class LoggerMetadata
{
    public string Destination { get; private set; }
    public LoggerMetadata(string destination)
    {
        this.Destination = destination;
    }
}
</pre>
</pre>
</div>
<p>Die Metadaten sollen dazu dienen, Filterkriterien zu definieren, die entscheiden, welche Instanzen zur Ausgabe herangezogen werden. Sicherlich könnte man diese Angaben auch direkt in den Logger legen. Dieses würde aber bedeuten, dass jeder Logger instanziiert werden muss, um auf diese Eigenschaften zugreifen zu können. Durch die Verwendung der Klasse <font face="Courier New">Lazy&lt;T, TMetadatea&gt;</font> ist der Zugriff auf die Metadaten möglich, ohne dass Instanzen der Logger existieren müssen.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:e80fd2f7-2581-4158-b9a0-510096ad8319" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
private List&lt; Lazy&lt; ILoggerClass, LoggerMetadata &gt; &gt; LazyLoggerClasses { get; set; }
</pre>
</pre>
</div>
<p>Da mehrere Varianten des Loggers zur Verfügung gestellt werden, sind diese in einer Eigenschaft vom Typ <font face="Courier New">List&lt;T&gt;</font> abgelegt. Die Loggerklasse und die Metadaten werden von <font face="Courier New">Lazy&lt;T, TMetadata&gt;</font> gekapselt.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:47b67633-8be5-4a67-9be8-1f97c871065f" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
private void CreateLogger()
{
    LazyLoggerClasses = new List&lt; Lazy&lt; ILoggerClass, LoggerMetadata &gt; &gt;();

    LazyLoggerClasses.Add(new Lazy&lt; ILoggerClass,
                          LoggerMetadata &gt;(() =&gt; { return new ShortFormatLogger(); },
                                           new LoggerMetadata(&quot;Trace&quot;)));

    LazyLoggerClasses.Add(new Lazy&lt; ILoggerClass,
                          LoggerMetadata &gt;(() =&gt; { return new ShortFormatLogger(); },
                                           new LoggerMetadata(&quot;Debug&quot;)));

    LazyLoggerClasses.Add(new Lazy&lt; ILoggerClass,
                          LoggerMetadata &gt;(() =&gt; { return new LongFormatLogger(); },
                                           new LoggerMetadata(&quot;Debugger&quot;)));
}
</pre>
</pre>
</div>
<p>Im Konstruktor von <font face="Courier New">Lazy&lt;T, TMetadata&gt;</font> wird ein Delegate vom Typ <font face="Courier New">Func&lt;ILoggerClass&gt;</font> erwartet. Dieser Delegate gibt die gewünschte Instanz des Loggers zurück. Der zweite Parameter enthält das Objekt mit den Metadaten. Per Konstruktor wird der Klasse für die Metadaten ein String übergeben, der über die Eigenschaft <font face="Courier New">Destination</font> abgefragt werden kann.</p>
<p>Die Methode <font face="Courier New">Write()</font> nutzt diese Eigenschaft, um nur auf die gewünschten Logger zuzugreifen. Hierzu wird mit Hilfe eines Lambda-Ausdrucks und der Methode <font face="Courier New">FindAll()</font> eine Liste zurückgegeben, in der alle Elemente enthalten sind, die den Filterkriterien entsprechen. Die <font face="Courier New">foreach</font>-Schleife greift über die Eigenschaft <font face="Courier New">Value</font> der Klasse <font face="Courier New">Lazy&lt;T, TMetadaten&gt;</font> auf den Logger zu.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:4e07c4c8-0946-4903-bbc8-8410476784ff" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
private void Write(string destination, string message)
{
    var outputs = LazyLoggerClasses.FindAll(a =&gt; a.Metadata.Destination.Contains(destination));
    foreach (var lazyDataClass in outputs)
        lazyDataClass.Value.WriteMessage(message);
}
</pre>
</pre>
</div>
<p>Der Hauptteil des Beispiels ruft zuerst die Methode für das Erzeugen der Logger-Objekte auf. Anschließend werden (als Test) die Metadaten angezeigt und zum Schluss die Meldungen ausgegeben.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:7d8c00f9-3676-4245-ba0f-b25e25ae4569" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
void Run()
{
    Console.WriteLine(&quot;-- Create some logger objects with metadata --&quot;);
    this.CreateLogger();

    Console.WriteLine(&quot;-- Read the metadata --&quot;);
    foreach (var lazyDataClass in LazyLoggerClasses)
        Console.WriteLine(lazyDataClass.Metadata.Destination);

    Console.WriteLine(&quot;-- Invoke the method of LoggerClass --&quot;);
    Write(&quot;Debug&quot;, &quot;message for debug&quot;);
    Write(&quot;Trace&quot;, &quot;message for trace&quot;);
    Write(&quot;Release&quot;, &quot;message for release&quot;);
}
</pre>
</pre>
</div>
<p>In der Ausgabe ist gut zu erkennen, dass erst dann der Konstruktor aufgerufen wird, wenn das erste Mal auf die Methode <font face="Courier New">WriteMessage()</font> zugegriffen wird. Der Zugriff auf die Metadaten erzeugt noch kein Objekt des Loggers.</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/12/commandwindowsample01.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="CommandWindowSample01" border="0" alt="CommandWindowSample01" src="http://stefanhenneken.files.wordpress.com/2011/12/commandwindowsample01_thumb.png?w=509&h=267" width="509" height="267"></a></p>
<p>Der Aufruf <font face="Courier New">Write(”Debug”, “message for debug”)</font> gibt zwei Meldungen aus, da als Filter der String <font face="Courier New">Debug</font> angegeben wurde und zwei Logger in den Metadaten (die Eigenschaft <font face="Courier New">Destination</font>) ebenfalls den String <font face="Courier New">Debug</font> bzw. <font face="Courier New">Debugger</font> enthalten.</p>
<p><font face="Courier New">Write(”Trace”, “message for trace”)</font> gibt nur eine Meldung aus, da der String <font face="Courier New">Trace</font> nur auf einen Logger zutrifft.</p>
<p>Durch <font face="Courier New">Write(”Release”, “message for release”)</font> wird keine Meldung ausgegeben, da <font face="Courier New">Release</font> auf keinen der Logger zutrifft.</p>
<p><a href="https://skydrive.live.com/embed?cid=8B31FEFE60F74DF4&amp;resid=8B31FEFE60F74DF4%21178&amp;authkey=AC0_IHQp4pNeU6w">Beispiel 1 (Visual Studio 2010)</a></p>
<p>Auch wenn dieses ein eher ‘sinnfreies’ Beispiel ist, zeigt es doch, dass im Zusammenhang mit Lazy-Loading die Klasse<font face="Courier New"> Lazy&lt;T, TMetadaten&gt;</font> sinnvoll eingesetzt werden kann.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/stefanhenneken.wordpress.com/328/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/stefanhenneken.wordpress.com/328/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/stefanhenneken.wordpress.com/328/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/stefanhenneken.wordpress.com/328/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/stefanhenneken.wordpress.com/328/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/stefanhenneken.wordpress.com/328/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/stefanhenneken.wordpress.com/328/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/stefanhenneken.wordpress.com/328/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/stefanhenneken.wordpress.com/328/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/stefanhenneken.wordpress.com/328/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/stefanhenneken.wordpress.com/328/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/stefanhenneken.wordpress.com/328/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/stefanhenneken.wordpress.com/328/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/stefanhenneken.wordpress.com/328/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=328&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://stefanhenneken.wordpress.com/2011/12/06/einsatz-von-lazyt-tmetadata-ohne-mef/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/a7a976e45ac7dd401c2765a06bc71cbb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">stefanhenneken</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/12/classdiagram_thumb.png" medium="image">
			<media:title type="html">ClassDiagram</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/12/commandwindowsample01_thumb.png" medium="image">
			<media:title type="html">CommandWindowSample01</media:title>
		</media:content>
	</item>
		<item>
		<title>MEF Teil 8 &#8211; Eigenen ExportProvider erstellen</title>
		<link>http://stefanhenneken.wordpress.com/2011/11/20/mef-teil-8-eigenen-exportprovider-erstellen/</link>
		<comments>http://stefanhenneken.wordpress.com/2011/11/20/mef-teil-8-eigenen-exportprovider-erstellen/#comments</comments>
		<pubDate>Sun, 20 Nov 2011 17:02:00 +0000</pubDate>
		<dc:creator>Stefan Henneken</dc:creator>
				<category><![CDATA[Managed Extensibility Framework]]></category>
		<category><![CDATA[ComposablePart]]></category>
		<category><![CDATA[ComposablePartDefinition]]></category>
		<category><![CDATA[CompositionBatch]]></category>
		<category><![CDATA[ContractBasedImportDefinition]]></category>
		<category><![CDATA[Export]]></category>
		<category><![CDATA[ExportDefinition]]></category>
		<category><![CDATA[ExportProvider]]></category>
		<category><![CDATA[ImportDefinition]]></category>
		<category><![CDATA[MEF]]></category>

		<guid isPermaLink="false">https://stefanhenneken.wordpress.com/?p=321</guid>
		<description><![CDATA[Das Managed Extensibility Framework (MEF) kann durch verschiedene Möglichkeiten erweitert werden. Eine Variante sind eigene Export-Provider. Ein Export-Provider macht genau das, was der Name schon aussagt, er stellt Exports der Klasse CompositionContainer zur Verfügung. Wie die Exports gefunden und instanziiert werden, ist komplett unter eigener Kontrolle. Eine weitere Variante ist die Benutzung der Klasse CompositionBatch, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=321&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Das Managed Extensibility Framework (MEF) kann durch verschiedene Möglichkeiten erweitert werden. Eine Variante sind eigene Export-Provider. Ein Export-Provider macht genau das, was der Name schon aussagt, er stellt Exports der Klasse <font face="Courier New">CompositionContainer</font> zur Verfügung. Wie die Exports gefunden und instanziiert werden, ist komplett unter eigener Kontrolle. Eine weitere Variante ist die Benutzung der Klasse <font face="Courier New">CompositionBatch</font>, die allerdings deutlich weniger Möglichkeiten bietet.</p>
<p><span id="more-321"></span>
<p>Die Verwendung von MEF ist mehr als einfach. Klassen, Methoden oder Eigenschaften werden mit den Attributen <font face="Courier New">Export</font> und <font face="Courier New">Import</font> dekoriert. Container und Kataloge sorgen dafür, dass die Exports zu den passenden Imports finden. Manchmal ist es aber nötig, diesen Prozess selber zu kontrollieren. Eine davon ist die Verwendung der Klasse <font face="Courier New">CompositionBatch</font>. </p>
<h1>Die Klasse CompositionBatch</h1>
<p>Die Klasse kann man sich als Liste von ComposableParts vorstellen.</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/11/classcompositionbatch.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ClassCompositionBatch" border="0" alt="ClassCompositionBatch" src="http://stefanhenneken.files.wordpress.com/2011/11/classcompositionbatch_thumb.png?w=451&h=260" width="451" height="260"></a></p>
<p>Mit den Methoden <font face="Courier New">AddPart()</font> und <font face="Courier New">RemovePart()</font> können Objekte vom Typ <font face="Courier New">ComposablePart</font> hinzugefügt oder gelöscht werden. Es gibt von der Methode <font face="Courier New">AddPart()</font> auch eine Variante, die als Parameter ein <font face="Courier New">Object</font> erwartet. Auf diese Weise lassen sich beliebige Objekte hinzufügen.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:7cceb7d0-2686-49f7-ac1a-0bae6a61790b" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true; wrap-lines: false;">
class Program
{
    [ImportMany]
    private ICarContract[] CarParts { get; set; }

    static void Main(string[] args)
    {
        new Program().Run();
    }

    void Run()
    {
        var container = new CompositionContainer();
        var batch = new CompositionBatch();
        ComposablePart partHost = batch.AddPart(this);
        ComposablePart partBMW = batch.AddPart(new BMW());
        ComposablePart partMercedes = batch.AddPart(new Mercedes());
        container.Compose(batch);

        foreach (ICarContract carPart in CarParts)
            Console.WriteLine(carPart.GetName());

        container.Dispose();
    }
}

public interface ICarContract
{
    string GetName();
}

[Export(typeof(ICarContract))]
public class Mercedes : ICarContract
{
    public string GetName()
    {
        return &quot;Mercedes&quot;;
    }
}

public class BMW : ICarContract
{
    public string GetName()
    {
        return &quot;BMW&quot;;
    }
}
</pre>
</pre>
</div>
<p>Mit der Methode <font face="Courier New">AddPart()</font> wird je eine Instanz von <font face="Courier New">BMW</font> und <font face="Courier New">Mercedes</font> der Klasse <font face="Courier New">CompositionBatch</font> hinzugefügt. Außerdem muss eine Instanz der Klasse <font face="Courier New">Program</font> übergeben werden, da dort der Import definiert ist. Da die Klasse <font face="Courier New">BMW</font> nicht mit dem Attribut <font face="Courier New">Export</font> dekoriert wurde, kann es nicht mit der Eigenschaft <font face="Courier New">CarParts</font> verlinkt werden. Wird das Programm ausgeführt, so ist nur das Objekt der Klasse <font face="Courier New">Mercedes</font> in dem Array <font face="Courier New">CarParts</font> enthalten. </p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/11/commandwindowsample01.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="CommandWindowSample01" border="0" alt="CommandWindowSample01" src="http://stefanhenneken.files.wordpress.com/2011/11/commandwindowsample01_thumb.png?w=373&h=139" width="373" height="139"></a></p>
<p><a href="https://skydrive.live.com/embedicon.aspx/Blog/2011/MEF-Teil8/Sample01.zip?cid=8b31fefe60f74df4&amp;sc=documents">Beispiel 1 (Visual Studio 2010)</a></p>
<p>Mit der Klasse <font face="Courier New">CompositionBatch</font> hat man unter Kontrolle, welche ComposableParts genutzt werden und welche eben nicht. Allerdings müssen alle Objekte mit dem Attribute <font face="Courier New">Export</font> dekoriert werden. Noch flexibler ist der Einsatz eines eigenen Export-Providers. Das später folgende Beispiel zeigt, wie auch Klassen berücksichtigt werden können, die nicht mit dem Attribut <font face="Courier New">Export</font> dekoriert wurden. Doch zuvor müssen zum Verständnis einige Klassen genauer betrachtet werden.</p>
<h1>Aufbau von MEF</h1>
<p>Das Managed Extensibility Framework kann in drei Ebenen aufgeteilt werden. Zum einem gibt es die Klassen, mit der das attributbasierte Programmiermodell umgesetzt wird. Eine weitere Ebene definiert die Container. Die Primitives sind die wichtigsten internen Systemklassen.</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/11/layersofmef.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="LayersOfMEF" border="0" alt="LayersOfMEF" src="http://stefanhenneken.files.wordpress.com/2011/11/layersofmef_thumb.png?w=640&h=431" width="640" height="431"></a></p>
<p>Der Container-Layer hat keine Abhängigkeiten zum attributbasierten Programmiermodell, sondern nur zu den Primitives, die direkt vom Container benutzt werden. Dadurch kann das attributbasierte Programmiermodell ausgetauscht werden, ohne dass der Container neu implementiert werden muss.</p>
<h1>Die Klasse ComposablePart</h1>
<p>Zentraler Bestandteil von MEF ist die Klasse <font face="Courier New">ComposablePart</font>. Über Exports stellen ComposableParts ihre Funktionalitäten anderen Systemen zur Verfügung. Sollen Funktionalitäten anderer Systeme verwendet werden, so geschieht dieses über Imports. Über die Auflistungen <font face="Courier New">ExportDefinitions</font> und <font face="Courier New">ImportDefinitions</font> verwaltet die Klasse ihre Imports und Exports.</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/11/classcomposablepart.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ClassComposablePart" border="0" alt="ClassComposablePart" src="http://stefanhenneken.files.wordpress.com/2011/11/classcomposablepart_thumb.png?w=427&h=260" width="427" height="260"></a></p>
<h1>Die Klasse ComposablePartDefinition</h1>
<p>Vereinfacht gesagt beschreibt die Klasse <font face="Courier New">ComposablePartDefinition</font> ein <font face="Courier New">ComposablePart</font>. <font face="Courier New">ComposablePartDefinition</font> stellt die <font face="Courier New">ImportDefinition</font> und <font face="Courier New">ExportDefinition</font> zur Verfügung. Diese sind notwendig, um mit der Methode <font face="Courier New">CreatePart()</font> ComposableParts zu erzeugen.</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/11/classcomposablepartdefinition.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ClassComposablePartDefinition" border="0" alt="ClassComposablePartDefinition" src="http://stefanhenneken.files.wordpress.com/2011/11/classcomposablepartdefinition_thumb.png?w=355&h=223" width="355" height="223"></a></p>
<p>Somit kann die Klasse <font face="Courier New">ComposablePartDefinition</font> als Erzeugerklasse (Factory class) für ComposableParts gesehen werden. Die Eigenschaften <font face="Courier New">ExportDefinitions</font>, <font face="Courier New">ImportDefinitions</font> und <font face="Courier New">Metadata</font> werden beim Anlegen über die Methode <font face="Courier New">CreatePart()</font> an das ComposablePart übergeben.</p>
<h1>Die Klasse ImportDefinition</h1>
<p>Die Klasse findet Verwendung bei <font face="Courier New">ComposablePart</font>. Die Klasse <font face="Courier New">ComposablePart</font> enthält die Eigenschaft <font face="Courier New">ImportDefinitions</font> die eine Auflistung von <font face="Courier New">ImportDefinition</font> darstellt.</p>
<p>Vereinfacht ausgedrückt definiert die Klasse <font face="Courier New">ImportDefinition</font> einen ‘Filter’ der entscheidet, welche Exports welchem Import zugeordnet werden.</p>
<p>Für jedes Attribut <font face="Courier New">Import</font> wird eine Instanz von <font face="Courier New">ImportDefinition</font> angelegt. </p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/11/classimportdefinition.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ClassImportDefinition" border="0" alt="ClassImportDefinition" src="http://stefanhenneken.files.wordpress.com/2011/11/classimportdefinition_thumb.png?w=595&h=417" width="595" height="417"></a></p>
<p>Drei Eigenschaften sind bei dieser Klasse besonders wichtig.</p>
<table border="1" cellspacing="0" cellpadding="0" width="598">
<tbody>
<tr>
<td valign="top" width="111"><strong>Eigenschaft</strong></td>
<td valign="top" width="485"><strong>Bedeutung</strong></td>
</tr>
<tr>
<td valign="top" width="111"><font face="Courier New">ContractName</font></td>
<td valign="top" width="485">Der Vertragsname ist immer ein String. Wird bei den Attributen <font face="Courier New">Import</font> oder <font face="Courier New">Export</font> nichts weiter angegeben, so wird der Datentyp der Variable genommen, an der das Attribut steht.<br />Im Konstruktor der Klasse <font face="Courier New">ImportAttribute</font> und <font face="Courier New">ExportAttribute</font> kann auch direkt ein String angegeben werden (<font face="Courier New">[Export(“MyContractName”)]</font>). Sehr verbreitet ist auch die Variante, im Konstruktor eine Variable vom Typ <font face="Courier New">Type</font> anzugeben. In diesem Fall wird der Fully Qualified Name als Vertragsname benutzt (<font face="Courier New">[Export(typeof(IContract)]</font><font face="Verdana">). Die Eigenschaft <font face="Courier New">ContractName</font> hat nichts mit dem eigentlichen Datentyp des Exports oder Imports zu tun. </font></td>
</tr>
<tr>
<td valign="top" width="111"><font face="Courier New">Cardinality</font></td>
<td valign="top" width="485"><font face="Courier New">ImportCardinality</font> ist ein enum und kann die folgenden Werte haben:<br /><font face="Courier New">ZeroOrOne</font>: kein oder ein Export wird erwartet.<br /><font face="Courier New">ExactlyOne</font>: Genau ein Export wird erwartet<br /><font face="Courier New">ZeroOrMode</font>: kein oder beliebig viele Exports werden erwartet.</td>
</tr>
<tr>
<td valign="top" width="111"><font face="Courier New">Constraint</font></td>
<td valign="top" width="485">Diese Eigenschaft kann einen Lambda-Ausdruck enthalten. Hier findet die eigentliche Entscheidung statt, ob und welcher Export zurückgegeben wird.</td>
</tr>
</tbody>
</table>
<h1>Die Klasse ContractBasedImportDefinition</h1>
<p>Die Klasse <font face="Courier New">ContractBasedImportDefinition</font> wird von <font face="Courier New">ImportDefinition</font> abgeleitet. Da bei der Eigenschaft <font face="Courier New">Constraint</font> kein Lambda-Ausdruck verwendet wird, ist die Handhabung in einigen Fällen einfacher. </p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/11/classbasedimportdefinition.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ClassBasedImportDefinition" border="0" alt="ClassBasedImportDefinition" src="http://stefanhenneken.files.wordpress.com/2011/11/classbasedimportdefinition_thumb.png?w=595&h=465" width="595" height="465"></a></p>
<h1>Die Klasse ExportDefinition</h1>
<p>Wie weiter oben zu sehen ist, wird die Klasse <font face="Courier New">ExportDefinition</font> bei der Eigenschaft <font face="Courier New">Constraint</font> der Klasse <font face="Courier New">ImportDefinition</font> benutzt. Während die Klasse <font face="Courier New">ImportDefinition</font> definiert, welcher Export bei einem Import benötigt wird, definiert die Klasse <font face="Courier New">ExportDefinition</font> den Export an sich. </p>
<p>Ebenfalls findet die Klasse Verwendung bei <font face="Courier New">ComposablePart</font>. Die Klasse <font face="Courier New">ComposablePart</font> enthält die Eigenschaft <font face="Courier New">ExportDefinitions,</font> die eine Auflistung von <font face="Courier New">ExportDefinition</font> darstellt.</p>
<p>Ähnlich der Klasse <font face="Courier New">ImportDefinition</font> wird für jedes Attribut <font face="Courier New">Export</font> eine Instanz von <font face="Courier New">ExportDefinition</font> angelegt. </p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/11/classexportdefinition.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ClassExportDefinition" border="0" alt="ClassExportDefinition" src="http://stefanhenneken.files.wordpress.com/2011/11/classexportdefinition_thumb.png?w=499&h=319" width="499" height="319"></a></p>
<p>Die Klasse <font face="Courier New">ExportDefinition</font> besteht im Wesentlichen aus den Eigenschaften <font face="Courier New">ContractName</font> und <font face="Courier New">Metadata</font>. <font face="Courier New">ContractName</font> beinhaltet den Namen des Schnittstellenvertrages. Der Vertragsname eines Exports muss mit dem eines Imports übereinstimmen. Die Eigenschaft <font face="Courier New">Metadata</font> beinhaltet ein <font face="Courier New">Dictionary</font> mit zusätzlichen Informationen, die andere Anwendungen auswerten können. </p>
<h1>Die Klasse Export</h1>
<p>Die Klasse <font face="Courier New">Export</font> repräsentiert einen Export. Wird das attributbasierte Programmiermodell verwendet, so ist dieses ein Objekt, das mit dem Attribut <font face="Courier New">Export</font> dekoriert wurde.</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/11/classexport.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ClassExport" border="0" alt="ClassExport" src="http://stefanhenneken.files.wordpress.com/2011/11/classexport_thumb.png?w=331&h=279" width="331" height="279"></a></p>
<h1>Klassenübersicht</h1>
<p>Im Folgenden sind nochmals alle besprochenen Klassen gegenübergestellt.</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/11/classoverview.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="ClassOverview" border="0" alt="ClassOverview" src="http://stefanhenneken.files.wordpress.com/2011/11/classoverview_thumb.png?w=691&h=542" width="691" height="542"></a></p>
<h1>Die Klasse ExportProvider</h1>
<p>Ausgangspunkt für einen eigenen Export-Provider ist die abstrakte Klasse <font face="Courier New">ExportProvider</font>. Von dieser Klasse muss der eigene Export-Provider abgeleitet werden. MEF liefert schon einige Klasse mit, die von <font face="Courier New">ExportProvider</font> abgeleitet sind. Die bekannteste Klasse ist <font face="Courier New">CompositionContainer</font>.</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/11/vererbungexportprovider.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="VererbungExportProvider" border="0" alt="VererbungExportProvider" src="http://stefanhenneken.files.wordpress.com/2011/11/vererbungexportprovider_thumb.png?w=451&h=565" width="451" height="565"></a></p>
<p>Eine der wichtigsten Methoden ist <font face="Courier New">GetExportsCore()</font>: </p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:e91e45e4-279a-4b8b-ab54-3cd54f0eb5fa" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true; wrap-lines: false;">
protected abstract IEnumerable&lt; Export &gt; GetExportsCore(ImportDefinition definition,
                                                        AtomicComposition atomicComposition)
</pre>
</pre>
</div>
<p>Die Methode erwartet u.a. die Definition des Imports, abgebildet durch die Klasse <font face="Courier New">ImportDefinition</font>. In erster Linie ist damit der Vertragsname vom Import gemeint. Zurückgeliefert wird eine Auflistung der Exports, die den gewünschten Kriterien entsprechen.</p>
<p>Des weiteren gibt es in der Klasse <font face="Courier New">ExportProvider</font> eine große Anzahl von Methoden, die mit <font face="Courier New">GetExport…()</font> beginnen. Diese Methoden brauchen bei einem eigenen Export-Provider nicht implementiert werden. Sie dienen nur dazu, den Aufruf der Methode <font face="Courier New">GetExportsCore()</font> auf verschiedene Art und Weise zu kapseln.</p>
<h1>Export-Provider an den Container übergeben</h1>
<p>Ein oder mehrere Export-Provider werden über den Konstruktor an den Container übergeben. Es stehen zwei Varianten zur Verfügung:</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:d64e63f8-cf55-483c-82bf-4a12d31c0d03" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
public CompositionContainer(params ExportProvider[] providers)

public CompositionContainer(ComposablePartCatalog catalog,
                            params ExportProvider[] providers)
</pre>
</pre>
</div>
<p>Ähnlich wie bei Katalogen, gibt es auch bei den Export-Providern eine Aggregate-Klasse, <font face="Courier New">AggregateExportProvider</font>. Diese enthält eine Liste von Objekten, die von <font face="Courier New">ExportProvider</font> abgeleitet sind. Jeder Export-Provider wird dieser Liste hinzugefügt. Kataloge werden über die Klasse <font face="Courier New">CatalogExportProvider</font> der Aggregate-Klasse hinzugefügt. Die Klasse <font face="Courier New">CatalogExportProvider</font> hat die Eigenschaft <font face="Courier New">Catalog</font> und kann Objekte vom Typ <font face="Courier New">ComposeablePartCatalog</font> (wie z. B. also <font face="Courier New">AssemblyCatalog</font>, <font face="Courier New">DirectoryCatalog</font>, <font face="Courier New">TypeCatalog</font>, ..) aufnehmen. Somit sieht der Container nur Export-Provider. Entweder eigene Export-Provider oder Kataloge, die mit Hilfe der Klasse <font face="Courier New">CatalogExportProvider</font> in einen Export-Provider verpackt wurden.</p>
<h1>Beispiel</h1>
<p>Das folgende Beispiel ähnelt sehr dem ersten Beispiel. Allerdings wird dem Container eine Instanz der Klasse <font face="Courier New">AssemblyCatalog</font> übergeben. Über diesen Katalog sollen die Klassen gefunden werden, die mit dem Attribut <font face="Courier New">Export</font> dekoriert wurden. Bei diesem Beispiel ist es die Klasse <font face="Courier New">Mercedes</font>. Das zweite Objekt, das an den Container übergeben wird, ist der Export-Provider <font face="Courier New">MyExportProvider</font>. Die Klasse ist von <font face="Courier New">ExportProvider</font> abgeleitet und erwartet im Konstruktor den Vertragsname und den Typ des Objektes, das der Container berücksichtigen soll (die Klasse <font face="Courier New">BMW</font>). Der Vertragsname muss natürlich der gleiche sein wie beim Import. Der Typ des Objektes wird hier als Fully Qualified Name angegeben. </p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:2f86e7e8-80d7-49f4-afd0-479065089f5e" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
public class Program
{
    [ImportMany]
    private ICarContract[] CarParts { get; set; }

    static void Main(string[] args)
    {
        new Program().Run();
    }

    void Run()
    {
        CompositionContainer container = null;

        try
        {
            var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
            var provider = new MyExportProvider(typeof(ICarContract).FullName,
                                                typeof(BMW).FullName);
            container = new CompositionContainer(catalog, provider);
            container.ComposeParts(this);

            foreach (ICarContract carPart in CarParts)
                Console.WriteLine(carPart.GetName());
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.Message);
        }
        container.Dispose();
    }
}

public interface ICarContract
{
    string GetName();
}

[Export(typeof(ICarContract))]
public class Mercedes : ICarContract
{
    public string GetName()
    {
        return &quot;Mercedes&quot;;
    }
}

public class BMW : ICarContract
{
    public string GetName()
    {
        return &quot;BMW&quot;;
    }
}
</pre>
</pre>
</div>
<p>Im Konstruktor der Klasse <font face="Courier New">MyExportProvider</font> wird ein Objekt der Klasse <font face="Courier New">Export</font> angelegt. Wichtig sind hierbei die Metadaten. Über die Metadaten wird der zugrunde liegende Datentyp übergeben (<font face="Courier New">Sample02.ICarContract</font>). Bei diesem Beispiel ist das gleichzeitig auch der Vertragsname. Im Debugger sieht das Objekt <font face="Courier New">export</font> wie folgt aus:&nbsp;
<p><a href="http://stefanhenneken.files.wordpress.com/2011/11/watchwindow01.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="WatchWindow01" border="0" alt="WatchWindow01" src="http://stefanhenneken.files.wordpress.com/2011/11/watchwindow01_thumb.png?w=580&h=239" width="580" height="239"></a> </p>
<p>Durch den Aufruf von <font face="Courier New">ComposeParts()</font> im Hauptprogramm, wird im Export-Provider die Methode <font face="Courier New">GetExportsCore()</font> aufgerufen. Hier wird entschieden, welche Exports zu dem Import passen. Erzeugt wird das Objekt in der Methode CreatePart(). Diese wird über den Delegate <font face="Courier New">funcCreatePart</font> für jedes Objekt vom Typ <font face="Courier New">Export</font>, das im Konstruktor erzeugt wurde, einmal aufgerufen. In diesem Beispiel wird einfach in der aktuellen Assembly nach dem gewünschten Typ gesucht und eine Instanz erzeugt. </p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:c0fd99ea-9039-4cac-9bb1-ede2ea9a215d" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true; wrap-lines: false;">
public class MyExportProvider : ExportProvider
{
    private List&lt; Export &gt; Exports { get; set; }
    private string TypeName { get; set; }

    public MyExportProvider(string contractName, string typeName)
    {
        Func&lt; object &gt; funcCreatePart = new Func&lt; object &gt;(CreatePart);
        this.TypeName = typeName;

        this.Exports = new List&lt; Export &gt;();
        var metadata = new Dictionary&lt; string, object &gt;();
        metadata.Add(CompositionConstants.ExportTypeIdentityMetadataName,
                     contractName);

        var exportDefinition = new ExportDefinition(contractName, metadata);
        var export = new Export(exportDefinition, funcCreatePart);
        this.Exports.Add(export);
    }

    public object CreatePart()
    {
        Type partType = Assembly.GetExecutingAssembly().GetType(this.TypeName);
        object instance = Activator.CreateInstance(partType);
        return instance;
    }

    protected override IEnumerable&lt; Export &gt; GetExportsCore(ImportDefinition definition,
                                                            AtomicComposition atomicComposition)
    {
        return this.Exports.Where(x =&gt; definition.IsConstraintSatisfiedBy(x.Definition));
    }
}
</pre>
</pre>
</div>
<p>Wie im ersten Beispiel wird auch hier die Klasse <font face="Courier New">BMW</font> nicht mit dem Attribut <font face="Courier New">Export</font> dekoriert. Trotzdem wird auch diese Klasse von MEF berücksichtigt. Möglich macht das der eigene Export-Provider, der unabhängig von den Attributen die gewünschte Instanz erzeugt. </p>
<p><a href="https://skydrive.live.com/embedicon.aspx/Blog/2011/MEF-Teil8/Sample02.zip?cid=8b31fefe60f74df4&amp;sc=documents">Beispiel 2 (Visual Studio 2010)</a></p>
<p>Wer an weiteren Informationen zu MEF interessiert ist, dem sei die MEF <a href="http://mef.codeplex.com/">CodePlex</a> Seite sehr empfohlen. Insbesondere der Bereich <a href="http://mef.codeplex.com/Wiki/View.aspx?title=Architecture">Architecture Overview</a> und der Artikel <a href="http://mef.codeplex.com/Project/Download/FileDownload.aspx?DownloadId=62133">Hosting the .NET Composition Primitives</a>. Hilfreich ist auch der Artikel von Klaus Aschenbrenner aus der Zeitschrift dotnetpro Ausgabe 07/2009.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/stefanhenneken.wordpress.com/321/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/stefanhenneken.wordpress.com/321/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/stefanhenneken.wordpress.com/321/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/stefanhenneken.wordpress.com/321/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/stefanhenneken.wordpress.com/321/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/stefanhenneken.wordpress.com/321/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/stefanhenneken.wordpress.com/321/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/stefanhenneken.wordpress.com/321/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/stefanhenneken.wordpress.com/321/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/stefanhenneken.wordpress.com/321/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/stefanhenneken.wordpress.com/321/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/stefanhenneken.wordpress.com/321/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/stefanhenneken.wordpress.com/321/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/stefanhenneken.wordpress.com/321/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=321&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://stefanhenneken.wordpress.com/2011/11/20/mef-teil-8-eigenen-exportprovider-erstellen/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/a7a976e45ac7dd401c2765a06bc71cbb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">stefanhenneken</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/11/classcompositionbatch_thumb.png" medium="image">
			<media:title type="html">ClassCompositionBatch</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/11/commandwindowsample01_thumb.png" medium="image">
			<media:title type="html">CommandWindowSample01</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/11/layersofmef_thumb.png" medium="image">
			<media:title type="html">LayersOfMEF</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/11/classcomposablepart_thumb.png" medium="image">
			<media:title type="html">ClassComposablePart</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/11/classcomposablepartdefinition_thumb.png" medium="image">
			<media:title type="html">ClassComposablePartDefinition</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/11/classimportdefinition_thumb.png" medium="image">
			<media:title type="html">ClassImportDefinition</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/11/classbasedimportdefinition_thumb.png" medium="image">
			<media:title type="html">ClassBasedImportDefinition</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/11/classexportdefinition_thumb.png" medium="image">
			<media:title type="html">ClassExportDefinition</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/11/classexport_thumb.png" medium="image">
			<media:title type="html">ClassExport</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/11/classoverview_thumb.png" medium="image">
			<media:title type="html">ClassOverview</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/11/vererbungexportprovider_thumb.png" medium="image">
			<media:title type="html">VererbungExportProvider</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/11/watchwindow01_thumb.png" medium="image">
			<media:title type="html">WatchWindow01</media:title>
		</media:content>
	</item>
		<item>
		<title>.NET User Group Tour</title>
		<link>http://stefanhenneken.wordpress.com/2011/10/09/net-user-group-tour/</link>
		<comments>http://stefanhenneken.wordpress.com/2011/10/09/net-user-group-tour/#comments</comments>
		<pubDate>Sun, 09 Oct 2011 16:40:00 +0000</pubDate>
		<dc:creator>Stefan Henneken</dc:creator>
				<category><![CDATA[in eigener Sache]]></category>
		<category><![CDATA[DNUG]]></category>
		<category><![CDATA[MEF]]></category>

		<guid isPermaLink="false">https://stefanhenneken.wordpress.com/2011/10/09/net-user-group-tour/</guid>
		<description><![CDATA[Zu dem Thema “Managed Extensibility Framework&#8217;” werde ich in den nächsten Monaten Vorträge in verschiedenen .NET User Groups halten. 10.10.2011 .NET User Group Paderborn 19.10.2011 .NET User Group Bielefeld 03.11.2011 .NET Developers Group Berlin Brandenburg 01.12.2011 .NET User Group Regensburg 28.03.2012 .NET User Group Rhein/Ruhr (Angaben ohne Gewähr) Schwerpunkte des Vortrags zum “Managed Extensibility Framework” [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=294&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Zu dem Thema “Managed Extensibility Framework&#8217;” werde ich in den nächsten Monaten Vorträge in verschiedenen .NET User Groups halten.</p>
<table border="1" cellspacing="0" cellpadding="0" width="549">
<tbody>
<tr>
<td valign="top" width="93">10.10.2011</td>
<td valign="top" width="454"><a href="http://www.dotnet-paderborn.de/">.NET User Group Paderborn</a></td>
</tr>
<tr>
<td valign="top" width="93">19.10.2011</td>
<td valign="top" width="454">.<a href="http://www.bielefeld-dotnet.de/">NET User Group Bielefeld</a></td>
</tr>
<tr>
<td valign="top" width="93">03.11.2011</td>
<td valign="top" width="454"><a href="http://www.dotnet-berlinbrandenburg.de/">.NET Developers Group Berlin Brandenburg</a></td>
</tr>
<tr>
<td valign="top" width="93">01.12.2011</td>
<td valign="top" width="454"><a href="http://www.dotnet-regensburg.de/">.NET User Group Regensburg</a></td>
</tr>
<tr>
<td valign="top" width="93">28.03.2012</td>
<td valign="top" width="454"><a href="http://ug-rheinruhr.tech.officelive.com">.NET User Group Rhein/Ruhr</a></td>
</tr>
</tbody>
</table>
<p>(Angaben ohne Gewähr)</p>
<p><span id="more-294"></span>
<p>Schwerpunkte des Vortrags zum “Managed Extensibility Framework” sind:</p>
<ul>
<li>Grundlagen und Prinzip
<li>Metadaten
<li>Lifecycle
<li>Creation Policy
<li>Composition und Recomposition
<li>Vererbung
<li>Debuggen</li>
</ul>
<ul>Gerne nehme ich weitere Einladungen an. Über Xing könnt ihr Kontakt zu mir aufnehmen.</ul>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/stefanhenneken.wordpress.com/294/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/stefanhenneken.wordpress.com/294/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/stefanhenneken.wordpress.com/294/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/stefanhenneken.wordpress.com/294/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/stefanhenneken.wordpress.com/294/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/stefanhenneken.wordpress.com/294/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/stefanhenneken.wordpress.com/294/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/stefanhenneken.wordpress.com/294/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/stefanhenneken.wordpress.com/294/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/stefanhenneken.wordpress.com/294/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/stefanhenneken.wordpress.com/294/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/stefanhenneken.wordpress.com/294/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/stefanhenneken.wordpress.com/294/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/stefanhenneken.wordpress.com/294/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=294&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://stefanhenneken.wordpress.com/2011/10/09/net-user-group-tour/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/a7a976e45ac7dd401c2765a06bc71cbb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">stefanhenneken</media:title>
		</media:content>
	</item>
		<item>
		<title>MEF Teil 7 &#8211; Exportieren &#252;ber eine Class Factory</title>
		<link>http://stefanhenneken.wordpress.com/2011/09/16/mef-teil-7-exportieren-ber-eine-class-factory/</link>
		<comments>http://stefanhenneken.wordpress.com/2011/09/16/mef-teil-7-exportieren-ber-eine-class-factory/#comments</comments>
		<pubDate>Fri, 16 Sep 2011 16:50:00 +0000</pubDate>
		<dc:creator>Stefan Henneken</dc:creator>
				<category><![CDATA[Managed Extensibility Framework]]></category>
		<category><![CDATA[MEF]]></category>

		<guid isPermaLink="false">https://stefanhenneken.wordpress.com/2011/09/16/mef-teil-7-exportieren-ber-eine-class-factory/</guid>
		<description><![CDATA[Über die Attribute Import und Export werden Objekte fest miteinander verbunden, vorausgesetzt, sie sind zueinander kompatibel. Nicht immer ist diese ‘feste’ Bindung erwünscht. Eine Class Factory kann hierbei helfen, diese starre Zuordnung aufzubrechen. Der mögliche Einsatz einer Class Factory soll durch zwei einfache Beispiele gezeigt werden. Ziel einer Class Factory ist es, Objekte zu erzeugen. [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=292&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Über die Attribute <font face="Courier New">Import</font> und <font face="Courier New">Export</font> werden Objekte fest miteinander verbunden, vorausgesetzt, sie sind zueinander kompatibel. Nicht immer ist diese ‘feste’ Bindung erwünscht. Eine Class Factory kann hierbei helfen, diese starre Zuordnung aufzubrechen. Der mögliche Einsatz einer Class Factory soll durch zwei einfache Beispiele gezeigt werden.</p>
<p><span id="more-292"></span>
<p>Ziel einer Class Factory ist es, Objekte zu erzeugen. Unterklassen entscheiden aber, welche Klasse genau instanziiert wird. Dazu liefert die Class Factory die passende Klasse in Abhängigkeiten von Informationen, die vom Client bereitgestellt werden oder erst zur Laufzeit ermittelt wurden.</p>
<p>Als Grundlage für die Beispiele soll ein Textlogger dienen, der über verschiedene Formatter den Ausgabetext unterschiedlich formatieren kann. In beiden Beispielen stellt die Klasse <font face="Courier New">ConsoleLogger</font> die Methode <font face="Courier New">Log()</font> bereit. Innerhalb der Klasse <font face="Courier New">ConsoleLogger</font> werden auf unterschiedliche Art und Weise Instanzen der Klasse <font face="Courier New">FormatterBase</font> (bzw. Ableitungen davon) erzeugt. Eine Ableitung (<font face="Courier New">FormatterTimeStamp</font>) ergänzt die Meldung mit der aktuellen Uhrzeit. Eine weitere Ableitung, die Klasse <font face="Courier New">FormatterDateTimeStamp</font>, gibt neben der Uhrzeit auch das aktuelle Datum aus.</p>
<p>Die Hauptanwendung, der Textlogger und der Formatter sollen über das Managed Extensibility Framework gebunden werden. Die eigentliche Implementierung des Formatters soll durch eine Class Factory flexibel erzeugt werden.</p>
<h3>Beispiel 1</h3>
<p>Der Host ist bei diesem Beispiel recht einfach aufgebaut. Eine Eigenschaft vom Typ <font face="Courier New">ConsoleLogger</font> importiert über das Managed Extensibility Framework die passende Instanz. Über die Methode <font face="Courier New">Log()</font> werden die Meldungen ausgegeben.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:5feda624-ee09-4991-85b0-40ea868062f0" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true; wrap-lines: false;">
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using Logger;

namespace Host
{
    class Program
    {
        [Import]
        public ConsoleLogger Logger { get; set; }

        static void Main(string[] args)
        {
            new Program().Run();
        }

        void Run()
        {
            var catalog = new DirectoryCatalog(&quot;.&quot;);
            var container = new CompositionContainer(catalog);
            container.ComposeParts(this);
            Logger.Log(&quot;Message A&quot;);
            Logger.Log(&quot;Message B&quot;);
            Logger.Log(&quot;Message C&quot;);
        }
    }
}
</pre>
</pre>
</div>
<p>Die Klasse <font face="Courier New">ConsoleLogger</font> enthält die Methode <font face="Courier New">Log()</font> und die Eigenschaft <font face="Courier New">FormatterFunc</font>. <font face="Courier New">FormatterFunc</font> ist ein Delegate vom Typ <font face="Courier New">Func&lt;FormatterBase&gt;</font>, liefert also immer ein Objekt vom Typ <font face="Courier New">FormatterBase</font> zurück.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:c109b9a6-2193-4787-b5f9-0e636713f552" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true; wrap-lines: false;">
using System;
using System.ComponentModel.Composition;
using Formatter;

namespace Logger
{
    [Export]
    public class ConsoleLogger
    {
        [Import]
        private Func&lt; FormatterBase &gt; FormatterFunc { get; set; }

        public void Log(string message)
        {
            string formattedString = FormatterFunc().Format(message);
            Console.WriteLine(formattedString);
        }
    }
}
</pre>
</pre>
</div>
<p>Exportiert wird die Methode aus der eigentlichen Class Factory. Die Methode <font face="Courier New">GetTextFormatter()</font> wurde hier mit dem Attribute <font face="Courier New">Export</font> versehen. Da diese kompatibel zu der Eigenschaft <font face="Courier New">FormatterFunc</font> ist, werden beide durch das Managed Extensibility Framework miteinander gebunden. </p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:9b6ec0f1-726d-4a52-805a-15e88967e714" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
public class FormatterFactory
{
    private static bool toogle;

    [Export]
    public FormatterBase GetTextFormatter()
    {
        // an dieser Stelle wird entschieden, welcher
        // Formatter zurückgeliefert werden soll.
        toogle = !toogle;
        if (toogle)
            return new FormatterTimeStamp();
        else
            return new FormatterDateTimeStamp();
    }
}}
</pre>
</pre>
</div>
<p>Die Methode <font face="Courier New">GetTextFormatter()</font> erzeugt beim Aufruf das gewünschte Objekt. Zu Testzwecken liefert diese Methode einfach abwechselnd zwei verschiedene Objekte zurück. Die Entscheidung, welches Objekt erzeugt wird, würde bei einer realen Applikation z.B. durch einen Parameter oder durch eine Konfigurationsdatei erfolgen.</p>
<p>Zum Schluss noch die Implementierung der einzelnen Formatter.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:4360e83c-f05a-4190-900a-51d514f192a8" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true; wrap-lines: false;">
public class FormatterBase
{
   public virtual string Format(string message)
   {
       return message;
   }
}

public class FormatterTimeStamp : FormatterBase
{
   public override string Format(string message)
   {
       return string.Format(&quot;{0} - {1}&quot;,
                            DateTime.Now.ToShortTimeString(),
                            message);
   }
}

public class FormatterDateTimeStamp : FormatterBase
{
    public override string Format(string message)
    {
       return string.Format(&quot;{0} {1} - {2}&quot;,
                            DateTime.Now.ToShortDateString(),
                            DateTime.Now.ToShortTimeString(),
                            message);
    }
}
</pre>
</pre>
</div>
<p>Wird das Programm gestartet, so erhält man folgende Ausgabe:</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/09/commandwindowsample01.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="CommandWindowSample01" border="0" alt="CommandWindowSample01" src="http://stefanhenneken.files.wordpress.com/2011/09/commandwindowsample01_thumb.png?w=424&h=170" width="424" height="170"></a></p>
<p><a href="https://skydrive.live.com/embedicon.aspx/Blog/2011/MEF-Teil7/Sample01.zip?cid=8b31fefe60f74df4&amp;sc=documents">Beispiel 1 (Visual Studio 2010)</a></p>
<h3>Beispiel 2</h3>
<p>Das zweite Beispiel ist dem ersten sehr ähnlich. Der entscheidende Unterschied ist der Aufruf der Methode <font face="Courier New">Log()</font>. Der Typ des Formatters wird in diesem Fall mit angegeben.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:3dc53270-963f-4d5c-b953-afbde8e3ca4f" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
using Formatter;
using Logger;

namespace Host
{
    class Program
    {
        [Import]
        public ConsoleLogger Logger { get; set; }

        static void Main(string[] args)
        {
            new Program().Run();
        }

        void Run()
        {
            var catalog = new DirectoryCatalog(&quot;.&quot;);
            var container = new CompositionContainer(catalog);
            container.ComposeParts(this);
            Logger.Log(&quot;Message&quot;, typeof(FormatterTimeStamp));
            Logger.Log(&quot;Message&quot;, typeof(FormatterDateTimeStamp));
        }
    }
}
</pre>
</pre>
</div>
<p>Die Klasse <font face="Courier New">ConsoleLogger</font> enthält wiederum die Methode <font face="Courier New">Log()</font> und die Eigenschaft <font face="Courier New">FormatterFunc</font>. <font face="Courier New">FormatterFunc</font> ist aber diesmal ein Delegate vom Typ <font face="Courier New">Func&lt;Type, FormatterBase&gt;</font>. <font face="Courier New">FormatterFunc</font> erwartet einen Parameter vom Typ <font face="Courier New">Type</font> und liefert ein Objekt vom Typ <font face="Courier New">FormatterBase</font> zurück.</p>
<p>Auch die Methode <font face="Courier New">Log()</font> enthält zusätzlich einen Parameter vom Typ <font face="Courier New">Type</font>. In der Methode <font face="Courier New">Log()</font> wird über den Delegate <font face="Courier New">FormatterFunc</font> der gewünschte Formatter angefordert. Welche Methode über den Delegate genau aufgerufen wird, hängt davon ab, welche Methode das Managed Extensibility Framework an den Delegate gebunden hat. In diesem Beispiel ist es die Methode <font face="Courier New">GetTextFormatter()</font> aus der Klasse <font face="Courier New">FormatterFactory</font>.&nbsp; </p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:b34fa404-eef0-4b44-b0fe-e87d72d5294a" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
using System;
using System.ComponentModel.Composition;
using Formatter;

namespace Logger
{
    [Export]
    public class ConsoleLogger
    {
        private FormatterBase formatterBase;

        [Import]        
        private Func&lt; Type, FormatterBase &gt; FormatterFunc { get; set; }

        public void Log(string message, Type formatterType)
        {
            FormatterBase formatterBase = FormatterFunc(formatterType);
            string formattedString = formatterBase.Format(message);
            Console.WriteLine(formattedString);
        }
    }
}
</pre>
</pre>
</div>
<p>Die Klasse <font face="Courier New">FormatterFactory</font> exportiert die passende Methode, die zu dem Delegate <font face="Courier New">FormatterFunc</font> der Klasse <font face="Courier New">ConsoleLogger</font> kompatibel ist. Innerhalb <font face="Courier New">GetTextFormatter()</font> wird von dem gewünschten Typ ein Objekt erzeugt und an die Methode <font face="Courier New">Log()</font> zurückgegeben. Hat die Methode <font face="Courier New">Log()</font> ein Formatter-Objekt erhalten, wird von diesem die Methode <font face="Courier New">Format()</font> aufgerufen und der formatierte Text ausgegeben.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:daa751f0-5d1e-4c5b-8878-c42dc0955b47" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
public class FormatterFactory
{
   [Export]
    public FormatterBase GetTextFormatter(Type controlType)
    {
        ConstructorInfo ci = controlType.GetConstructor(new Type[] { });
        FormatterBase formatterBase = (FormatterBase)ci.Invoke(new object[] { });
        return formatterBase;
    }
}
</pre>
</pre>
</div>
<p>Die Ausgabe des Beispiels:</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/09/commandwindowsample02.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="CommandWindowSample02" border="0" alt="CommandWindowSample02" src="http://stefanhenneken.files.wordpress.com/2011/09/commandwindowsample02_thumb.png?w=409&h=153" width="409" height="153"></a></p>
<p><a href="https://skydrive.live.com/embedicon.aspx/Blog/2011/MEF-Teil7/Sample02.zip?cid=8b31fefe60f74df4&amp;sc=documents">Beispiel 2 (Visual Studio 2010)</a></p>
<p>Die beiden Beispiele zeigen recht gut, wie eine Anwendung aus eigenständigen Modulen bestehen kann, ohne dass der Programmieraufwand extrem ansteigt. Der Einsatz einer Class Factory hilft, die Flexibilität zu erhöhen.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/stefanhenneken.wordpress.com/292/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/stefanhenneken.wordpress.com/292/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/stefanhenneken.wordpress.com/292/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/stefanhenneken.wordpress.com/292/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/stefanhenneken.wordpress.com/292/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/stefanhenneken.wordpress.com/292/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/stefanhenneken.wordpress.com/292/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/stefanhenneken.wordpress.com/292/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/stefanhenneken.wordpress.com/292/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/stefanhenneken.wordpress.com/292/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/stefanhenneken.wordpress.com/292/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/stefanhenneken.wordpress.com/292/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/stefanhenneken.wordpress.com/292/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/stefanhenneken.wordpress.com/292/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=292&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://stefanhenneken.wordpress.com/2011/09/16/mef-teil-7-exportieren-ber-eine-class-factory/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/a7a976e45ac7dd401c2765a06bc71cbb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">stefanhenneken</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/09/commandwindowsample01_thumb.png" medium="image">
			<media:title type="html">CommandWindowSample01</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/09/commandwindowsample02_thumb.png" medium="image">
			<media:title type="html">CommandWindowSample02</media:title>
		</media:content>
	</item>
		<item>
		<title>MEF Teil 6 &#8211; Constructor-Injection</title>
		<link>http://stefanhenneken.wordpress.com/2011/08/30/mef-teil-6-constructor-injection/</link>
		<comments>http://stefanhenneken.wordpress.com/2011/08/30/mef-teil-6-constructor-injection/#comments</comments>
		<pubDate>Tue, 30 Aug 2011 19:10:00 +0000</pubDate>
		<dc:creator>Stefan Henneken</dc:creator>
				<category><![CDATA[Managed Extensibility Framework]]></category>
		<category><![CDATA[Constructor-Injection]]></category>
		<category><![CDATA[ImportingConstructor]]></category>
		<category><![CDATA[MEF]]></category>

		<guid isPermaLink="false">https://stefanhenneken.wordpress.com/2011/08/30/mef-teil-6-constructor-injection/</guid>
		<description><![CDATA[Bei Constructor-Injection werden sämtliche Abhängigkeiten einer Klasse über den Konstruktor übergeben. Damit kann ein Objekt der Klasse nur erzeugt werden, wenn alle Abhängigkeiten bei der Erstellung vorhanden sind. Der Einsatz von Constructor-Injection mit dem Managed Extensibility Framework soll durch ein einfaches Beispiel vorgestellt werden. Die genannten Abhängigkeiten entstehen z. B. durch den Verweis eines Objekt [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=286&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Bei Constructor-Injection werden sämtliche Abhängigkeiten einer Klasse über den Konstruktor übergeben. Damit kann ein Objekt der Klasse nur erzeugt werden, wenn alle Abhängigkeiten bei der Erstellung vorhanden sind. Der Einsatz von Constructor-Injection mit dem Managed Extensibility Framework soll durch ein einfaches Beispiel vorgestellt werden.</p>
<p><span id="more-286"></span>
<p>Die genannten Abhängigkeiten entstehen z. B. durch den Verweis eines Objekt auf<br />ein anderes Objekt. Ohne die Anwendung von Constructor-Injection ist jedes Objekt selbst für die Erzeugung und Verwaltung seiner Abhängigkeiten zuständig. </p>
<h3>Das Attribut ImportingConstructor</h3>
<p>MEF benutzt zum Instanziieren von Komponenten immer den Standardkonstruktor. Soll ein anderer Konstruktor verwendet werden, so muss dieser mit dem Attribut <font face="Courier New">ImportingConstructor</font> dekoriert werden. Es darf nur ein Konstruktor das Attribut <font face="Courier New">ImportingConstructor</font> besitzen. Besitzen mehrere Konstruktoren das Attribut, kommt es zu einem Laufzeitfehler. Ebenfalls tritt ein Laufzeitfehler auf, wenn es keinen Standardkonstruktor gibt und kein Konstruktor mit dem Attribut <font face="Courier New">ImportingConstructor</font> dekoriert wurde. Interessant ist hier, dass die Konstruktoren ohne Probleme als <font face="Courier New">private</font> deklariert werden können. Alle Parameter des Konstruktors werden automatisch als Importe deklariert. Somit muss es in dem Host nur noch einen passenden Export geben.</p>
<p>Man kann (und man sollte auch) hier mit Vertragsnamen arbeiten. Spätestens wenn mehrere Parameter vom gleichen Typ vorhanden sind, ist dieses notwendig. Im Konstruktor wird hierzu das Attribut <font face="Courier New">Import</font> explizit vor jedem Parameter angegeben. Das Attribut <font face="Courier New">Export</font> im Host muss natürlich den gleichen Vertragsnamen erhalten.</p>
<p>Dekoration des Konstruktors mit dem Attribut <font face="Courier New">ImportingConstructor</font> bei einem Export.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:481e7066-dd5d-4b10-8d89-06c553e31ed4" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true; wrap-lines: false;">
[ImportingConstructor]
private Foo([Import(&quot;ConstructorParameter&quot;)]int parameter)
{
    Console.WriteLine(String.Format(&quot;Parameter: {0}.&quot;, parameter));
}
</pre>
</pre>
</div>
<p>Definition einer Eigenschaft innerhalb eines Imports. Die Eigenschaft wird beim Instanziieren des Exports an den Parameter des Konstruktors übergeben.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:89ff3ef5-6448-4149-b387-f4117d962db8" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp;">
[Export(&quot;ConstructorParameter&quot;)]
private int Parameter { get; set; }
</pre>
</pre>
</div>
<h3>Beispiel</h3>
<p>Das folgende Beispiel ist ein einfacher Logger, der Meldungen auf die Konsole ausgibt. Der Logger ist in der Klasse <font face="Courier New">ConsoleLogger</font> implementiert. Die Ausgabe kann individuell formatiert werden. Hierzu dient die Klasse <font face="Courier New">FormatterBase</font>, von der es zwei Ableitungen gibt. Jede dieser Ableitungen (<font face="Courier New">FormatterTimeStamp</font> und <font face="Courier New">FormatterDateTimeStamp</font>) formatieren die Ausgabe unterschiedlich. Die Klasse <font face="Courier New">ConsoleLogger</font> erwartet in seinem Konstruktor ein Objekt der Klasse <font face="Courier New">FormatterBase</font> (oder eine Ableitung davon). Über dieses Objekt, das in den Konstruktor injiziert wird, wird der Text ausgegeben. </p>
<p>Die Klasse <font face="Courier New">FormatterBase</font> mit den beiden Ableitungen <font face="Courier New">FormatterTimeStamp</font> und <font face="Courier New">FormatterDateTimeStamp</font><font face="Verdana">.</font></p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:3c406859-3796-43aa-8cc2-35aa9fecb97f" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
using System;

namespace Formatter
{
    public class FormatterBase
    {
        public virtual string Format(string message)
        {
            return message;
        }
    }

    public class FormatterTimeStamp : FormatterBase
    {
        public override string Format(string message)
        {
            return string.Format(&quot;{0} - {1}&quot;,
                                 DateTime.Now.ToShortTimeString(),
                                 message);
        }
    }

    public class FormatterDateTimeStamp : FormatterBase
    {
        public override string Format(string message)
        {
            return string.Format(&quot;{0} {1} - {2}&quot;,
                                  DateTime.Now.ToShortDateString(),
                                  DateTime.Now.ToShortTimeString(),
                                  message);
        }
    }
}
</pre>
</pre>
</div>
<p>Der Logger besitzt einen Konstruktor, der als Parameter ein Objekt vom Typ <font face="Courier New">FormatterBase</font> erwartet. Über dieses Objekt wird der Text formatiert und ausgegeben. Das Attribut <font face="Courier New">ImportingConstructor</font> gibt vor, welchen Konstruktor das Managed Extensibility Framework beim Instanziieren der Klasse benutzen soll. Der Parameter vom Konstruktor wurde hier explizit als Import deklariert.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:ccf9c26e-8100-469f-b77c-fd043ef8391d" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
using System;
using System.ComponentModel.Composition;
using Formatter;

namespace Logger
{
    [Export]
    public class ConsoleLogger
    {
        private FormatterBase formatter;

        [ImportingConstructor]
        public ConsoleLogger([Import(typeof(FormatterBase))]FormatterBase formatter)
        {
            this.formatter = formatter;
        }

        public void Log(string message)
        {
            string formattedString = this.formatter.Format(message);
            Console.WriteLine(formattedString);
        }
    }
}
</pre>
</pre>
</div>
<p>Die Hauptanwendung hat eine Eigenschaft mit dem Namen <font face="Courier New">Logger</font>, in der der Logger enthalten ist. Diese Eigenschaft besitzt das Attribut <font face="Courier New">Import</font>. Eine weitere Eigenschaft, ist der Parameter für den Konstruktor. Diese Eigenschaft muss vom gleichen Typ sein und außerdem den gleichen Vertragsnamen besitzen wie der Parameter vom Konstruktor.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:6b675d9d-32a9-4baa-b76a-04b753bf02a7" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using Formatter;
using Logger;

namespace Host
{
    class Program
    {
        [Import]
        public ConsoleLogger Logger { get; set; }

        [Export(typeof(FormatterBase))]
        private FormatterBase Formatter { get; set; }

        static void Main(string[] args)
        {
            new Program().Run();
        }
        void Run()
        {
            var catalog = new DirectoryCatalog(&quot;.&quot;);
            var container = new CompositionContainer(catalog);

            this.Formatter = new FormatterTimeStamp();
            //this.Formatter = new FormatterDateTimeStamp();

            container.ComposeParts(this);

            Logger.Log(&quot;Message&quot;);
        }
    }
}
</pre>
</pre>
</div>
<p>Vor Aufruf der Methode <font face="Courier New">ComposeParts()</font> wird die Eigenschaft <font face="Courier New">Formatter</font> mit dem gewünschten Objekt des Formatters gesetzt. MEF übergibt diese Eigenschaft an den Konstruktor der Klasse <font face="Courier New">ConsoleLogger</font>. Auf diese Weise kann per Constructor-Injection festgelegt werden, wie die Ausgabe des Loggers formatiert wird.</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/08/commandwindowssample012.png"><img style="background-image:none;border-bottom:0;border-left:0;padding-left:0;padding-right:0;display:inline;border-top:0;border-right:0;padding-top:0;" title="CommandWindowsSample01" border="0" alt="CommandWindowsSample01" src="http://stefanhenneken.files.wordpress.com/2011/08/commandwindowssample01_thumb2.png?w=417&h=153" width="417" height="153"></a></p>
<p>Das Beispiel wurde so erstellt, dass Hauptanwendung, Logger und Formatter in unterschiedlichen Assemblies liegen. So kann z.B. die DLL für den Formatter ausgetauscht werden, ohne dass die Hauptanwendung angefasst werden muss.</p>
<p><a href="https://skydrive.live.com/embedicon.aspx/Blog/2011/MEF-Teil6/Sample01.zip?cid=8b31fefe60f74df4&amp;sc=documents">Beispiel 1 (Visual Studio 2010)</a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/stefanhenneken.wordpress.com/286/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/stefanhenneken.wordpress.com/286/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/stefanhenneken.wordpress.com/286/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/stefanhenneken.wordpress.com/286/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/stefanhenneken.wordpress.com/286/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/stefanhenneken.wordpress.com/286/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/stefanhenneken.wordpress.com/286/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/stefanhenneken.wordpress.com/286/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/stefanhenneken.wordpress.com/286/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/stefanhenneken.wordpress.com/286/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/stefanhenneken.wordpress.com/286/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/stefanhenneken.wordpress.com/286/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/stefanhenneken.wordpress.com/286/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/stefanhenneken.wordpress.com/286/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=286&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://stefanhenneken.wordpress.com/2011/08/30/mef-teil-6-constructor-injection/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/a7a976e45ac7dd401c2765a06bc71cbb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">stefanhenneken</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/08/commandwindowssample01_thumb2.png" medium="image">
			<media:title type="html">CommandWindowsSample01</media:title>
		</media:content>
	</item>
		<item>
		<title>MEF Teil 5 &#8211; Composition und Recomposition</title>
		<link>http://stefanhenneken.wordpress.com/2011/08/24/mef-teil-5-composition-und-recomposition/</link>
		<comments>http://stefanhenneken.wordpress.com/2011/08/24/mef-teil-5-composition-und-recomposition/#comments</comments>
		<pubDate>Wed, 24 Aug 2011 20:02:00 +0000</pubDate>
		<dc:creator>Stefan Henneken</dc:creator>
				<category><![CDATA[Managed Extensibility Framework]]></category>
		<category><![CDATA[AggregateCatalog]]></category>
		<category><![CDATA[AssemblyCatalog]]></category>
		<category><![CDATA[ComposablePartCatalog]]></category>
		<category><![CDATA[Composition]]></category>
		<category><![CDATA[CompositionBatch]]></category>
		<category><![CDATA[CompositionContainer]]></category>
		<category><![CDATA[DeploymentCatalog]]></category>
		<category><![CDATA[DirectoryCatalog]]></category>
		<category><![CDATA[MEF]]></category>
		<category><![CDATA[Recomposition]]></category>
		<category><![CDATA[TypeCatalog]]></category>

		<guid isPermaLink="false">https://stefanhenneken.wordpress.com/2011/08/24/mef-teil-5-composition-und-recomposition/</guid>
		<description><![CDATA[Die Kataloge und Container dienen dazu, die Instanzen der Composable Parts zu erzeugen und miteinander zu binden. In den vorherigen Blogs wurde dieses Thema nicht weiter behandelt. Das soll jetzt nachgeholt werden. Composition Composable Parts sind Objekte (Klassen, Schnittstellen, Methoden oder Eigenschaften), die mit dem Attribut Import, ImportMany oder Export dekoriert werden. Composable Parts, die [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=280&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Die Kataloge und Container dienen dazu, die Instanzen der Composable Parts zu erzeugen und miteinander zu binden. In den vorherigen Blogs wurde dieses Thema nicht weiter behandelt. Das soll jetzt nachgeholt werden.</p>
<p><span id="more-280"></span><br />
<h3>Composition</h3>
<p>Composable Parts sind Objekte (Klassen, Schnittstellen, Methoden oder Eigenschaften), die mit dem Attribut <font face="Courier New">Import</font>, <font face="Courier New">ImportMany</font> oder <font face="Courier New">Export</font> dekoriert werden. Composable Parts, die als Export definiert wurden, werden vom Managed Extensibility Framework geladen und instanziiert. Die Composable Parts, die als Import deklariert wurden, sind Variablen, an welche die Exports gebunden werden. Im einfachsten Fall wird ein Import an ein Export gebunden. Das ist allerdings nur möglich, wenn beide Parts zueinander kompatibel sind.</p>
<p>Das Managed Extensibility Framework unterstützt die Instanziierung und das Binden mit den sogenannten Katalogen und Containern. Kataloge kontrollieren das Laden der Composable Parts, während Container die Instanzen der Exports erzeugen und diese mit den Imports binden.</p>
<h5>Die Klasse ComposablePartCatalog</h5>
<p>Von der Klasse <font face="Courier New">ComposablePartCatalog</font> gibt es verschiedene Ableitungen. Die verschiedenen Ableitungen sind notwendig, da es mehrere Möglichkeiten gibt, Composable Parts zu laden. Zu finden sind die Klassen in dem Namespace <font face="Courier New">System.ComponentModel.Composition.Hosting</font>. Composable Parts können sich in der gleichen Assembly befinden oder auf mehreren Assemblies verteilt sein. Des weiteren muss unterschieden werden, ob die Assemblies statisch oder dynamisch geladen werden.</p>
<table border="1" cellspacing="0" cellpadding="0" width="578">
<tbody>
<tr>
<td valign="top" width="144"><strong>Klasse</strong></td>
<td valign="top" width="432"><strong>Funktion</strong></td>
</tr>
<tr>
<td valign="top" width="144"><font face="Courier New">TypeCatalog</font></td>
<td valign="top" width="432">Die Klasse <font face="Courier New">TypeCatalog</font> ermöglicht das Binden von exakt angegebenen Typen.</td>
</tr>
<tr>
<td valign="top" width="144"><font face="Courier New">AssemblyCatalog</font></td>
<td valign="top" width="432">Sollen Composable Parts aus einer angegebenen Assembly berücksichtigt werden, so wird die Klasse <font face="Courier New">AssemblyCatalog</font> benutzt.</td>
</tr>
<tr>
<td valign="top" width="144"><font face="Courier New">DirectoryCatalog</font></td>
<td valign="top" width="432">Es werden nur Assemblies aus einem bestimmten Verzeichnis geladen.</td>
</tr>
<tr>
<td valign="top" width="144"><font face="Courier New">AggregateCatalog</font></td>
<td valign="top" width="432">Mehrere Kataloge können mit Hilfe dieser Klasse kombiniert werden.</td>
</tr>
<tr>
<td valign="top" width="144"><font face="Courier New">DeploymentCatalog</font></td>
<td valign="top" width="432">Steht unter Silverlight zur Verfügung und dient dazu XAPs nachzuladen.</td>
</tr>
</tbody>
</table>
<h5>Die Klasse CompositionContainer</h5>
<p>Über die Klasse <font face="Courier New">CompositionContainer</font> wird das Laden und Binden der Composable Parts gestartet. Hierzu wird dem Konstruktor der Klasse <font face="Courier New">CompositionContainer</font> als Parameter der Katalog übergeben. Die Methode <font face="Courier New">ComposeParts()</font> startet den Composing Prozess. Als Parameter muss der Methode <font face="Courier New">ComposeParts()</font> die Referenz auf das Objekt übergeben werden, das die Imports enthält. Alternativ kann aber auch die Methode Compose() aufgerufen werden, die eine Instanz der Klasse <font face="Courier New">CompositionBatch</font> erwartet.</p>
<h5>Die Klasse CompositionBatch</h5>
<p>Der Methode <font face="Courier New">Compose()</font> der Klasse <font face="Courier New">CompositionContainer</font> kann als Parameter eine Instanz der Klasse <font face="Courier New">CompositionBatch</font> übergeben werden. <font face="Courier New">CompositionBatch</font> verwaltet eine Liste von Composable Parts, die beim Composing Prozess berücksichtigt werden sollen. </p>
<h5>Beispiel</h5>
<p>Das folgende Beispiel zeigt die Benutzung aller genannten Klassen.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:4a363f4e-21dc-4df0-babb-427a7e5d0c61" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true; wrap-lines: false;">
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using CarContract;

namespace CarHost
{
    class Program
    {
        [ImportMany(typeof(ICarContract), AllowRecomposition=true)]
        private IEnumerable&lt;ICarContract&gt; CarParts { get; set; }

        static void Main(string[] args)
        {
            new Program().Run();
        }
        void Run()
        {
            var catalog = new AggregateCatalog();

            // Parameterliste mit Klassen, die berücksichtigt werden sollen
            var typeCatalog = new TypeCatalog(typeof(CarMercedes.Mercedes),
                                                     typeof(CarAudi.Audi));
            catalog.Catalogs.Add(typeCatalog);
           
            // Assembly wird über den FullName dynamisch geladen und
            // dem Katalog hinzugefügt
            var assemblyCatalog = new AssemblyCatalog(
                                             Assembly.Load(
                                                      &quot;Opel,
                                                       Version=1.0.0.0,
                                                       Culture=neutral,
                                                       PublicKeyToken=null&quot;));
            catalog.Catalogs.Add(assemblyCatalog);
            
            // Assemblies aus dem Verzeichnis '.\AddIn' werden berücksichtigt
            var directoryCatalog = new DirectoryCatalog(@&quot;.\AddIn&quot;);
            catalog.Catalogs.Add(directoryCatalog);

            // Container mit dem entsprechenden Katalog anlegen
            var container = new CompositionContainer(catalog);

            // Composition über die Klasse CompositionBatch starten
            var batch = new CompositionBatch();
            batch.AddPart(this);
            container.Compose(batch);

            // Composition ohne CompositionBatch starten
            //container.ComposeParts(this);
            // eine Parameterliste von Objekten kann auch angegeben werden
            //container.ComposeParts(this, obj1, obj2);

            // Anzeige aller Composable Parts
            foreach (ICarContract car in CarParts)
                Console.WriteLine(car.GetName());

            container.Dispose();
        }
    }
}
</pre>
</pre>
</div>
<p>Die Ausgabe des Beispielprogramms sieht wie folgt aus:</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/08/commandwindowssample01.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="CommandWindowsSample01" border="0" alt="CommandWindowsSample01" src="http://stefanhenneken.files.wordpress.com/2011/08/commandwindowssample01_thumb.png?w=425&h=189" width="425" height="189"></a></p>
<p><a href="https://skydrive.live.com/embedicon.aspx/Blog/2011/MEF-Teil5/Sample01.zip?cid=8b31fefe60f74df4&amp;amp;sc=documents">Beispiel 1 (Visual Studio 2010)</a></p>
<h3>Recomposition</h3>
<p>Mit Recomposition bezeichnet man die Möglichkeit, weitere Composable Parts zur Laufzeit nachzuladen. Vorstellbar wäre z.B. eine Anwendung, die von einer externen Quelle zusätzliche Komponenten nachlädt. </p>
<p>MEF ist so ausgelegt, dass ein Recomposition nicht möglich ist. Soll Recomposition unterstützt werden, so muss bei dem Attribut <font face="Courier New">Import</font> oder <font face="Courier New">ImportMany</font> die Eigenschaft <font face="Courier New">AllowRecomposition</font> auf TRUE gesetzt werden.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:0cbd931d-f3a3-4b66-b62b-178905dd76d6" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; pad-line-numbers: true;">
[ImportMany(typeof(ICarContract), AllowRecomposition=true)]
</pre>
</pre>
</div>
<p>Recomposition kann nur über die Kataloge <font face="Courier New">DirectoryCatalog</font> und <font face="Courier New">AggregateCatalog</font> genutzt werden. Die Klasse <font face="Courier New">DirectoryCatalog</font> bietet hierzu speziell die Methode <font face="Courier New">Refresh()</font> an. Diese lädt alle Composable Parts erneut aus dem Verzeichnis des Katalogs.</p>
<p>Mit <font face="Courier New">AggregateCatalog</font> kann die Liste der Kataloge komplett neu aufgebaut werden. Somit lässt sich die Zusammenstellung der Composable Parts zur Laufzeit neu zusammensetzen. Hierzu ein kleines Beispiel.</p>
<div style="display:inline;float:none;margin:0;padding:0;" id="scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:2dcc39a7-2eba-4eb7-9bad-23f69d325c1d" class="wlWriterEditableSmartContent">
<pre style="white-space:normal;">
<pre class="brush: csharp; wrap-lines: false;">
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using CarContract;

namespace CarHost
{
    class Program
    {
        [ImportMany(typeof(ICarContract), AllowRecomposition=true)]
        private IEnumerable&lt; ICarContract &gt; CarParts { get; set; }

        static void Main(string[] args)
        {
            new Program().Run();
        }
        void Run()
        {
            var aggregateCatalog = new AggregateCatalog();

            aggregateCatalog.Catalogs.Add(new DirectoryCatalog(@&quot;.\AddIn01&quot;));
            var container = new CompositionContainer(aggregateCatalog);
            container.ComposeParts(this);

            foreach (ICarContract car in CarParts)
                Console.WriteLine(car.GetName());
                
            Console.WriteLine(&quot;\n...weitere Parts laden...\n&quot;);

            aggregateCatalog.Catalogs.Add(new DirectoryCatalog(@&quot;.\AddIn02&quot;));
            container.ComposeParts(this);

            foreach (ICarContract car in CarParts)
                Console.WriteLine(car.GetName());

            container.Dispose();
        }
    }
}
</pre>
</pre>
</div>
<p>Am Anfang wird ein Objekt der Klasse <font face="Courier New">AggregateCatalog</font> angelegt. Dieser Katalog verwaltet eine Liste mit weiteren Katalogen. In diesem Beispiel enthält die Liste ein <font face="Courier New">DirectoryCatalog</font> mit dem Unterverzeichnis <em>AddIn01</em>. Die Zeilen 26 und 27 rufen von allen gefundenen Composable Parts die Methode <font face="Courier New">GetName()</font> auf. Ab Zeile 31 wird die Liste um einen weiteren Katalog ergänzt. Dieses zweite Objekt der Klasse <font face="Courier New">DirectoryCatalog</font> verweist auf das Verzeichnis <em>AddIn02</em>.</p>
<p><a href="http://stefanhenneken.files.wordpress.com/2011/08/commandwindowssample011.png"><img style="background-image:none;padding-left:0;padding-right:0;display:inline;padding-top:0;border-width:0;" title="CommandWindowsSample01" border="0" alt="CommandWindowsSample01" src="http://stefanhenneken.files.wordpress.com/2011/08/commandwindowssample01_thumb1.png?w=409&h=225" width="409" height="225"></a></p>
<p>Auf diese Weise lässt sich die Liste der zu berücksichtigen Kataloge beliebig anpassen. Neben dem Hinzufügen ist es auch möglich, Kataloge mit den Methoden <font face="Courier New">Clear()</font> und <font face="Courier New">Remove()</font> zu entfernen. In diesem Fall werden die Composable Parts von MEF zerstört.</p>
<p><a href="https://skydrive.live.com/embedicon.aspx/Blog/2011/MEF-Teil5/Sample02.zip?cid=8b31fefe60f74df4&amp;amp;sc=documents">Beispiel 2 (Visual Studio 2010)</a></p>
<p>Wird das Anpassen der Liste mit den Katalogen asynchron durchgeführt, so muss darauf geachtet werden, dass die Composable Parts thread-safe sind. Der Konstruktor der Composable Parts wird immer im Kontext des Threads ausgeführt, aus dem die Methode <font face="Courier New">ComposeParts()</font> der Klasse <font face="Courier New">CompositionContainer</font> aufgerufen wird. </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/stefanhenneken.wordpress.com/280/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/stefanhenneken.wordpress.com/280/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/stefanhenneken.wordpress.com/280/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/stefanhenneken.wordpress.com/280/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/stefanhenneken.wordpress.com/280/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/stefanhenneken.wordpress.com/280/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/stefanhenneken.wordpress.com/280/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/stefanhenneken.wordpress.com/280/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/stefanhenneken.wordpress.com/280/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/stefanhenneken.wordpress.com/280/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/stefanhenneken.wordpress.com/280/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/stefanhenneken.wordpress.com/280/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/stefanhenneken.wordpress.com/280/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/stefanhenneken.wordpress.com/280/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=stefanhenneken.wordpress.com&#038;blog=16394787&#038;post=280&#038;subd=stefanhenneken&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://stefanhenneken.wordpress.com/2011/08/24/mef-teil-5-composition-und-recomposition/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/a7a976e45ac7dd401c2765a06bc71cbb?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">stefanhenneken</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/08/commandwindowssample01_thumb.png" medium="image">
			<media:title type="html">CommandWindowsSample01</media:title>
		</media:content>

		<media:content url="http://stefanhenneken.files.wordpress.com/2011/08/commandwindowssample01_thumb1.png" medium="image">
			<media:title type="html">CommandWindowsSample01</media:title>
		</media:content>
	</item>
	</channel>
</rss>
