Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Let's dissect your code sample:</p> <pre><code>filenames.SelectMany(f =&gt; Assembly.LoadFrom(f).GetCustomAttributes(typeof(PluginClassAttribute), true) .Cast&lt;PluginClassAttribute&gt;() .Select(a =&gt; a.PluginType) ).ToList(); </code></pre> <p>So, we start off with a <code>string[]</code> called <code>filenames</code>. We invoke the <code>SelectMany</code> extension method on the array, and then we invoke <code>ToList</code> on the result:</p> <pre><code>filenames.SelectMany( ... ).ToList(); </code></pre> <p><code>SelectMany</code> takes a delegate as parameter, in this case the delegate must take one parameter of the type <code>string</code> as input, and return an <code>IEnumerable&lt;T&gt;</code> (Where the type of <code>T</code> is inferred). This is where lambdas enter the stage:</p> <pre><code>filenames.SelectMany(f =&gt; Assembly.LoadFrom(f).GetCustomAttributes(typeof(PluginClassAttribute), true) ).ToList() </code></pre> <p>What will happen here is that <em>for each</em> element in the <code>filenames</code> array, the delegate will be invoked. <code>f</code> is the input parameter, and whatever comes to the right of <code>=&gt;</code> is the method body that the delegate refers to. In this case, <code>Assembly.LoadFrom</code> will be invoked for filename in the array, passing he filename into the <code>LoadFrom</code> method using the <code>f</code> argument. On the <code>AssemblyInstance</code> that is returned, <code>GetCustomAttributes(typeof(PluginClassAttribute), true)</code> will be invoked, which returns an array of <code>Attribute</code> instances. So the compiler can not infer that the type of <code>T</code> mentioned earlier is <code>Assembly</code>.</p> <p>On the <code>IEnumerable&lt;Attribute&gt;</code> that is returned, <code>Cast&lt;PluginClassAttribute&gt;()</code> will be invoked, returning an <code>IEnumerable&lt;PluginClassAttribute&gt;</code>.</p> <p>So now we have an <code>IEnumerable&lt;PluginClassAttribute&gt;</code>, and we invoke <code>Select</code> on it. The <code>Select</code> method is similar to <code>SelectMany</code>, but returns a single instance of type <code>T</code> (which is inferred by the compiler) instead of an <code>IEnumerable&lt;T&gt;</code>. The setup is identical; for each element in the <code>IEnumerable&lt;PluginClassAttribute&gt;</code> it will invoke the defined delegate, passing the current element value into it:</p> <pre><code>.Select(a =&gt; a.PluginType) </code></pre> <p>Again, <code>a</code> is the input parameter, <code>a.PluginType</code> is the method body. So, for each <code>PluginClassAttribute</code> instance in the list, it will return the value of the <code>PluginType</code> property (I will assume this property is of the type <code>Type</code>).</p> <p><strong>Executive Summary</strong><br> If we glue those bits and pieces together:</p> <pre><code>// process all strings in the filenames array filenames.SelectMany(f =&gt; // get all Attributes of the type PluginClassAttribute from the assembly // with the given file name Assembly.LoadFrom(f).GetCustomAttributes(typeof(PluginClassAttribute), true) // cast the returned instances to PluginClassAttribute .Cast&lt;PluginClassAttribute&gt;() // return the PluginType property from each PluginClassAttribute instance .Select(a =&gt; a.PluginType) ).ToList(); </code></pre> <hr> <p><strong>Lambdas vs. Delegates</strong><br> Let's finish this off by comparing lambdas to delegates. Take the following list:</p> <pre><code>List&lt;string&gt; strings = new List&lt;string&gt; { "one", "two", "three" }; </code></pre> <p>Say we want to filter out those that starts with the letter "t":</p> <pre><code>var result = strings.Where(s =&gt; s.StartsWith("t")); </code></pre> <p>This is the most common approach; set it up using a lambda expression. But there are alternatives:</p> <pre><code>Func&lt;string,bool&gt; func = delegate(string s) { return s.StartsWith("t");}; result = strings.Where(func); </code></pre> <p>This is essentially the same thing: first we create a delegate of the type <code>Func&lt;string, bool&gt;</code> (that means that it takes a <code>string</code> as input parameter, and returns a <code>bool</code>). Then we pass that delegate as parameter to the <code>Where</code> method. This is what the compiler did for us behind the scenes in the first sample (<code>strings.Where(s =&gt; s.StartsWith("t"));</code>).</p> <p>One third option is to simply pass a delegate to a non-anonymous method:</p> <pre><code>private bool StringsStartingWithT(string s) { return s.StartsWith("t"); } // somewhere else in the code: result = strings.Where(StringsStartingWithT); </code></pre> <p>So, in the case that we are looking at here, the lambda expression is a rather compact way of defining a delegate, typically referring an anonymous method.</p> <p>And if you had the energy read all the way here, well, thanks for your time :)</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload