tag:blogger.com,1999:blog-71094824359255659232024-03-08T02:51:02.115-05:00The Never-Ending StaircaseAn eternal series of steps in software development.Brooke Philpotthttp://www.blogger.com/profile/08943147081689036679noreply@blogger.comBlogger8125tag:blogger.com,1999:blog-7109482435925565923.post-52065823556673462602014-03-14T16:23:00.000-04:002014-07-08T11:46:23.095-04:00SQL Sentry 8.0 Technology UpdateThis content has been moved to the new unified SQL Sentry blog:<br />
<a href="http://blogs.sqlsentry.com/brookephilpott/sql-sentry-v8-technology-update/">SQL Sentry 8.0 Technology Update</a>Brooke Philpotthttp://www.blogger.com/profile/08943147081689036679noreply@blogger.com0tag:blogger.com,1999:blog-7109482435925565923.post-25587026896590898692010-02-19T15:53:00.001-05:002011-01-12T14:45:01.605-05:00Caching and Memoization<p>A while back Wes Dyer wrote a great article on <a href="http://blogs.msdn.com/wesdyer/archive/2007/01/26/function-memoization.aspx">function memoization</a>, a technique used to speed up subsequent function evaluations by caching the results of previous executions based on input value.</p> <p>In a nutshell, given a function f(x), <br />m(f(x)) = <br />if (precomputed x is stored) <br />return precomputed x <br />else <br />precomputed x = f(x) <br />store precomputed(x) <br />return f(x)</p> <p>Memoization is frequently used when the following conditions are true: <br />1. Input values of x are frequently recalculated <br />2. f(x) takes enough time to execute that the speedup for computing f(x) outweighs by a large margin the lookup times for finding the precomputed value of f(x). <br />3. There are not so many distinct values of x as to cause memory to overflow for all the precomputed values that will be cached. Memoization would not be helpful to calculate across a set of 10^10 distinct input values, for example.</p> <p>The examples Wes gave are great and I strongly encourage you to read his article. This article was written to expand on that article by applying some additional concepts. The primary issue I had with straightforward memoization was item #3. Let us assume we have a long running function f(x). We then want to apply the following logic:</p> <p>Define a cache timeout time t. <br />If we have computed f(x) within t, then return the cached value of f(x). <br />If we have not, then recalculate f(x) and update the cache.</p> <p>This solves item #3 fairly gracefully. As long as the number of input values of x do not vary by more than n new items in time t, you can have support for an infinite values of x, as long as you understand how x is changing in time t. It also solves the issue of eviction of stale values from the cache. So knowing what I wanted to do let’s look at the implementation.</p> <p>The class I created was called CachedFunction<T, TKey, TResult> where T is the input type that can be a class, TKey is a struct that can be reliably used as an key for the caching dictionary, and TResult is the output type of the function we are caching. I also created a simpler version when you have a function that takes a struct as an input value vs a class. In that case you can just use CachedFunction<T, TResult>. Internally that class just maps T->TKey via a 1-1 mapping function.</p> <p>Let’s look at an example:</p> <pre class="brush: csharp;">Func<int, int> addOne = x => { System.Threading.Thread.Sleep(1000); return x + 1; }; // Wait second and add a value<br />Action<int, TimeSpan> printTime = <br /> (x, time) => <br /> { <br /> string message = string.Format("result={0}, computationtime={1}", x, time); <br /> System.Diagnostics.Debug.WriteLine(message); <br /> }; // Helper for printing output<br /><br />var addOneCached = addOne.CreateCachedFunction(new TimeSpan(0, 1, 0)); // Create a caching version of the function with a one minute timeout<br />System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();<br />sw.Start();<br />var result = addOneCached(1); // Compute the value. Should take 1 second because of sleep.<br />printTime(result, sw.Elapsed);<br />sw.Reset();<br />sw.Start();<br />var result2 = addOneCached(1); // Compute the value. Should be instantaneous because it's cached.<br />printTime(result2, sw.Elapsed);<br />sw.Stop();<br /></pre><br /><br />And the results:<br />result=2, computationtime=00:00:01.0039687<br />result=2, computationtime=00:00:00.0005103<br /><br />Let’s look at the code, starting with the caching function itself:<br /><br /><pre class="brush: csharp;">using System;<br />using System.Collections.Generic;<br /><br />namespace Intercerve<br />{<br /> /// <summary><br /> /// Provides functionality for wrapping functions and caching computed values<br /> /// </summary><br /> /// <typeparam name="T"></typeparam><br /> /// <typeparam name="TKey"></typeparam><br /> /// <typeparam name="TResult"></typeparam><br /> [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1005:AvoidExcessiveParametersOnGenericTypes")]<br /> public class CachedFunction<T, TKey, TResult> where TKey : struct<br /> {<br /> /// <summary><br /> /// An internal class used to hold the time an individual result was cached and the corresponding value.<br /> /// </summary><br /> private class ResultAndCacheTime<br /> {<br /> /// <summary><br /> /// The value of the cached result.<br /> /// </summary><br /> public TResult Result { get; set; }<br /> /// <summary><br /> /// The time the value was cached.<br /> /// </summary><br /> public DateTime CacheTime { get; set; }<br /> }<br /><br /> private readonly Dictionary<TKey, ResultAndCacheTime> _Cache = new Dictionary<TKey, ResultAndCacheTime>();<br /> private readonly Func<T, TResult> _Function;<br /> private readonly Func<T, TKey> _KeyMap;<br /> private readonly TimeSpan _CacheTimeout;<br /> private readonly object _SyncLock = new object();<br /><br /> /// <summary><br /> /// Creates a new CachedFunction to provide automatic caching and eviction for computed values.<br /> /// </summary><br /> /// <param name="function">The function to wrap.</param><br /> /// <param name="keyMap">A mapping function that returns a key of type TKey for an input value of type T.</param><br /> /// <param name="cacheTimeout">The cache timeout threshold for flushing the cache.</param><br /> public CachedFunction(Func<T, TResult> function, Func<T, TKey> keyMap, TimeSpan cacheTimeout)<br /> {<br /> _Function = function;<br /> _KeyMap = keyMap;<br /> _CacheTimeout = cacheTimeout;<br /> }<br /><br /> /// <summary><br /> /// Computes the value of f(value) or returns the cached value if within the cache timeout threshold.<br /> /// </summary><br /> /// <param name="value">The value to retrieve the result for.</param><br /> /// <returns>The value of f(value) or the last cached value.</returns><br /> public TResult Compute(T value)<br /> {<br /> TKey key = _KeyMap(value);<br /> ResultAndCacheTime resultAndCacheTime;<br /><br /> lock (_SyncLock)<br /> {<br /> // Aquire the lock and see if we have the value already cached.<br /> if (_Cache.TryGetValue(key, out resultAndCacheTime))<br /> {<br /> // We already have the value. How old is it?<br /> TimeSpan elapsedTime = DateTime.UtcNow.Subtract(resultAndCacheTime.CacheTime);<br /> if (elapsedTime >= _CacheTimeout)<br /> {<br /> // The value is too old so remove it.<br /> _Cache.Remove(key);<br /> }<br /> else<br /> {<br /> // The value is within the cache threshold so return it.<br /> return resultAndCacheTime.Result;<br /> }<br /> }<br /> }<br /><br /> // We don't have the value cached. Compute the value. Note we don't hold the lock here.<br /> // This can result in the operating executing twice vs only computing the value once when we don't have it cached<br /> // but if we don't do this and hold _SyncLock while computing, it would make Compute(T value) a <br /> // blocking operation for the duration of _Function(value).<br /> TResult computedResult = _Function(value);<br /> resultAndCacheTime = new ResultAndCacheTime { Result = computedResult, CacheTime = DateTime.UtcNow };<br /><br /> lock (_SyncLock)<br /> {<br /> ResultAndCacheTime resultAndCacheTimeExisting;<br /> if (_Cache.TryGetValue(key, out resultAndCacheTimeExisting))<br /> {<br /> // This is for thread synchronization. _Function(value) could potentially take a long time, so<br /> // we cant hold the lock during it. Because of that we use a last win algorithm to see if two threads updated at the same time<br /> // If they did the last computed time wins<br /> if (resultAndCacheTime.CacheTime > resultAndCacheTimeExisting.CacheTime)<br /> {<br /> _Cache.Remove(key);<br /> _Cache.Add(key, resultAndCacheTime);<br /> }<br /> }<br /> else<br /> {<br /> _Cache.Add(key, resultAndCacheTime);<br /> }<br /> }<br /><br /> return computedResult;<br /> }<br /><br /> /// <summary><br /> /// Clears the entire cache all at once for all values.<br /> /// </summary><br /> public void ClearCache()<br /> {<br /> lock (_SyncLock)<br /> {<br /> _Cache.Clear();<br /> }<br /> }<br /><br /> /// <summary><br /> /// Clears a specific value from the cache.<br /> /// </summary><br /> public void ClearCacheForValue(T value)<br /> {<br /> TKey key = _KeyMap(value);<br /> lock (_SyncLock)<br /> {<br /> if (_Cache.ContainsKey(key))<br /> {<br /> _Cache.Remove(key);<br /> }<br /> }<br /> }<br /> }<br /><br /> /// <summary><br /> /// Provides functionality for wrapping functions and caching computed values<br /> /// </summary><br /> public class CachedFunction<T, TResult> where T : struct<br /> {<br /> private CachedFunction<T, T, TResult> _CachedFunction;<br /><br /> /// <summary><br /> /// Creates a new CachedFunction to provide automatic caching and eviction for computed values.<br /> /// </summary><br /> /// <param name="function">The function to wrap.</param><br /> /// <param name="cacheTimeout">The cache timeout threshold for flushing the cache.</param><br /> public CachedFunction(Func<T, TResult> function, TimeSpan cacheTimeout)<br /> {<br /> _CachedFunction = new CachedFunction<T, T, TResult>(function, GetKey, cacheTimeout);<br /> }<br /><br /> private T GetKey(T value)<br /> {<br /> return value;<br /> }<br /><br /> /// <summary><br /> /// Computes the result of value.<br /> /// </summary><br /> /// <param name="value">The value to evaluate.</param><br /> /// <returns>The result.</returns><br /> public TResult Compute(T value)<br /> {<br /> return _CachedFunction.Compute(value);<br /> }<br /><br /> /// <summary><br /> /// Clears the entire cache all at once for all values.<br /> /// </summary><br /> public void ClearCache()<br /> {<br /> _CachedFunction.ClearCache();<br /> }<br /><br /> /// <summary><br /> /// Clears a specific value from the cache.<br /> /// </summary><br /> public void ClearCacheForValue(T value)<br /> {<br /> _CachedFunction.ClearCacheForValue(value);<br /> }<br /> }<br />}<br /></pre><br /><br />That is relatively user friendly, but to create a caching function using that method we have to call:<br /><br /><pre class="brush: csharp;">var addOneCachedLong = new CachedFunction<int, int>(addOne, new TimeSpan(0, 1, 0)).GetFunction();</pre><br />To reduce the complexity we can create helper extension methods and use type inference to ease in the construction. To do so I defined the following:<br /><br /><pre class="brush: csharp;">using System;<br /><br />namespace Intercerve<br />{<br /> /// <summary><br /> /// Various extension methods for creating alternate versions of functions.<br /> /// </summary><br /> public static class FunctionExtensions<br /> {<br /> /// <summary><br /> /// Creates a caching wrapper around a function.<br /> /// </summary><br /> /// <typeparam name="T">The function argument type</typeparam><br /> /// <typeparam name="TResult">The function return type</typeparam><br /> /// <param name="function">The function to wrap</param><br /> /// <param name="cacheTimeout">The cache timeout for cached results</param><br /> /// <returns></returns><br /> public static Func<T, TResult> CreateCachedFunction<T, TResult>(this Func<T, TResult> function, TimeSpan cacheTimeout) where T : struct<br /> {<br /> CachedFunction<T, TResult> cachedFunction = new CachedFunction<T, TResult>(function, cacheTimeout);<br /> return cachedFunction.Compute;<br /> }<br /><br /> /// <summary><br /> /// Creates a caching wrapper around a function.<br /> /// </summary><br /> /// <typeparam name="T">The function argument type</typeparam><br /> /// <typeparam name="TKey">The cached item key type</typeparam><br /> /// <typeparam name="TResult">The function return type</typeparam><br /> /// <param name="function">The function to wrap</param><br /> /// <param name="keyMap">The mapping function from T to TKey</param><br /> /// <param name="cacheTimeout">The cache timeout for cached results</param><br /> /// <returns></returns><br /> public static Func<T, TResult> CreateCachedFunction<T, TKey, TResult>(this Func<T, TResult> function, Func<T, TKey> keyMap, TimeSpan cacheTimeout) where TKey : struct<br /> {<br /> CachedFunction<T, TKey, TResult> cachedFunction = new CachedFunction<T, TKey, TResult>(function, keyMap, cacheTimeout);<br /> return cachedFunction.Compute;<br /> }<br /> }<br />}<br /></pre><br /><br />We can then do what we did in the example, which is simply:<br /><pre class="brush: csharp;">var addOneCached = addOne.CreateCachedFunction(new TimeSpan(0, 1, 0));</pre><br /><br />I also added support for eviction of individual items on the cache if need be, or flushing the cache entirely. The primary usage I’ve found for the CachedFunction() was to add a bounded caching solution around a function that already had been written. It’s much easier to extend a method like this than to go into the guts and reorganize. During an optimization phase we noticed that certain database function calls were running very often. It was a tricky problem because we wanted to make a method call, but depending on various factors that method could run very often or not very often. We wanted to restrict how often the inner function ran.<br /><br /><p>Put another way, take a function outer(x) that calls inner(x). We can’t control how often outer(x) runs. Sometimes it could execute multiple times per second, sometimes once per minute. We can’t change that behavior. It needs to run as often as it needs to run. However inner(x) shouldn’t change that often. Most of the time its value is the same as it was the previous execution. Sometimes it can change but rarely. So we used this function to wrap inner(x) and make cached_inner(x) with a threshold of five minutes or so. Voila. Problem solved. No matter how often outer(x) runs, inner(x) will only run once every five minutes, but will always yield a value, and better yet, we did this without having to modify the original function and in one line of code.</p><br /><br /><p>Of course, right now this method only supports functions with one input parameter, however it wouldn’t be too hard to extend the class to support additional variables. Wes demonstrates how to do this easily in another excellent blog post: <a title="http://blogs.msdn.com/wesdyer/archive/2007/02/11/baby-names-nameless-keys-and-mumbling.aspx" href="http://blogs.msdn.com/wesdyer/archive/2007/02/11/baby-names-nameless-keys-and-mumbling.aspx">http://blogs.msdn.com/wesdyer/archive/2007/02/11/baby-names-nameless-keys-and-mumbling.aspx</a></p><br /><br /><p>Until next time…</p> Brooke Philpotthttp://www.blogger.com/profile/08943147081689036679noreply@blogger.com0tag:blogger.com,1999:blog-7109482435925565923.post-65317183981475421822010-02-05T14:17:00.001-05:002010-02-05T16:25:08.165-05:00Win32_Service Memory Leak<p>During the development of SQL Sentry 5.5 we noticed we were receiving errors from some of our watched development servers. The error was from the WMI subsystem and simply stated “Out of Memory.” After searching for a bit to try to determine the cause, we realized that on all the affected watched servers the wmiprvse.exe process was using around 512MB of memory. Doing some additional searches turned up the following blog post:</p> <p><a title="http://blogs.technet.com/askperf/archive/2008/09/16/memory-and-handle-quotas-in-the-wmi-provider-service.aspx" href="http://blogs.technet.com/askperf/archive/2008/09/16/memory-and-handle-quotas-in-the-wmi-provider-service.aspx">http://blogs.technet.com/askperf/archive/2008/09/16/memory-and-handle-quotas-in-the-wmi-provider-service.aspx</a></p> <p>in which Mark Ghazai, a member of the Windows Performance Team, discussed the wmiprvse.exe process and the 512 meg cap. In a nutshell, the wmiprvse.exe process is the WMI Provider Service, which acts as a host for WMI providers such as win32_service. It has a cap of 512 megabytes which can be adjusted, but in the case of a memory leak, that would just be a band-aid. We needed to get to the root of the problem. Why was this process spiking to 512MB to begin with?</p> <p>The first thing we noticed was that this problem only showed up on Windows 7 and Windows Server 2008 R2, so it was specific to Windows 6.1. It also happened only on systems we watched, which makes sense because we use WMI heavily. We could look at the wmiprvse.exe process throughout the day and see that the memory usage was steadily rising. A mitigating factor is that this process will actually terminate itself after a period of inactivity, but in the case of a monitoring system like SQL Sentry, we don’t ever wait long enough for that period of inactivity to elapse. The question remained, exactly what were we doing that was causing this process to increase in memory on Windows 7 and 2008 R2?</p> <p>The next step was to try to profile the process for a memory leak. A quick search in the Debugging Tools for Windows help document (WinDbg) revealed a helpful topic called “Using UMDH to Find a User-Mode Memory Leak.” Seeing as that was exactly what I wanted I started in earnest.</p> <p>The first step involves setting up your symbols. In order to analyze a memory leak you have to be able to look at the call stacks, and the only way you can get call stack information from an unmanaged executable is with symbols. Fortunately this is pretty easy since Microsoft provides symbol servers. The following command, taken from the documentation, can be used to set up the symbol path.</p> <p>set _NT_SYMBOL_PATH=c:\mysymbols;srv*c:\mycache*http://msdl.microsoft.com/download/symbols</p> <p>The next step was to use GFlags to enable UMDH stack traces as outlined in the WinDbg documentation. We started GFlags and turned on Stack Backtrace (Megs) for the wmiprvse.exe image by clicking the checkbox. After that you have to restart the process, so I just killed wmiprvse.exe. It gets auto-launched the first time a WMI query is executed, so it respawned right away.</p> <p>Once the process was running we needed to collect our allocation snapshots. To do so, you use: <br />umdh –p:<processid> –f:<logfilename> <br />Each time you run the above command, it generates a snapshot of the current allocations. What we are doing here is taking a peek at all the unmanaged memory allocations from the process and their corresponding call stacks. So I ran that once, waited for the memory used by that process to increase by about 1 megabyte, then ran it again using a different log file name.</p> <p>The next step is to run these files back through umdh to create a differential file. UMDH will compare the allocations in one file to the allocations in the other and determine what memory allocations made in the earlier file still exist and have not been cleaned up by the time the second file was created. This is done using the following command:</p> <p>umdh <file1> <file2> > <outfile></p> <p>The > before <outfile> is just a redirect showing where you want the output to go to. This will generate a new file which is readable. After the symbol listing at the top of the file are the allocations. Not everything in this list is a problem. Something could be in this list just because it hasn’t been cleaned up yet, but in our case, one entry always showed up at the top. Furthermore, the numbers got larger as time went on (I only included the top six lines of the call stack).</p> <p>+   c28ba ( 185174 - c28ba)   1078 allocs    BackTrace2980620 <br />+     83c (  1078 -   83c)    BackTrace2980620    allocations </p> <p>    ntdll! ?? ::FNODOBFM::`string'+0001A81B <br />    msvcrt!malloc+00000070 <br />    cimwin32!operator new+00000009 <br />    cimwin32!CWin32Service::LoadPropertyValuesWin2K+000004A1 <br />    cimwin32!CWin32Service::AddDynamicInstancesNT+00000200 <br />    framedynos!Provider::CreateInstanceEnum+00000034</p> <p>As you can see, CWin32Service is the leaky class, and I presumed that it was the code that supplied the functionality for the Win32_Service WMI provider. The next step was validating this outside our code, so I got on a system that SQL Sentry was not looking at to ensure there wasn’t any interference in my metrics and ran the following query in wbemtest:</p> <p>select * from win32_service</p> <p>Each time, the wmiprvse.exe process memory went up, but never down. I then decided to throw a heavier test at it, so I whipped up a little powershell function</p> <p>for ($i=0; $i -le100; $i++) { get-wmiobject win32_service | format-table  }</p> <p>Running that caused wmiprvse.exe to continually increase in memory while it was running, so I had my smoking gun and proceeded to file a bug report with Microsoft. </p> <p>So, where are we now? After going back and forth with Microsoft on this, they have filed it for the next major release of the OS, i.e. it won’t be fixed in Windows 7 or 2008 R2 in any service pack or hotfix. Apparently the changes are “too invasive.” We are currently working with Microsoft to see if we can escalate this and get it fixed. In the meantime we have other options for querying service status, like using the Service Control Manager, we’re just making sure that it doesn’t cause any issues that we’ve never seen before. In 5.5 we’ll be including an App.Config option called useScmForServiceStatus that we can turn on and off for testing, or to switch to SCM if WMI is causing problems in your environment.</p> Brooke Philpotthttp://www.blogger.com/profile/08943147081689036679noreply@blogger.com5tag:blogger.com,1999:blog-7109482435925565923.post-9873298274499336042009-01-19T14:34:00.001-05:002009-03-03T12:50:34.736-05:00The SQL Sentry Console is now 64-bit capable<p>I wanted to take a departure from the language-based posts I’ve done in the past and relay some information regarding the next release of our product. Starting with the next point release of our software (currently slated to be 4.3) The SQL Sentry Console will be able to run in native 64-bit mode. The reason for this blog post is to describe some of the reasons why this is available now and has not been in the past, as well as what it means to the end-user.</p> <p>SQL Sentry has two components, the SQL Sentry Console, and the SQL Sentry Server Service. Each one of these talks to a number of different systems and uses many supporting dlls/assemblies to provide support for external systems. The SQL Sentry Server Service has run natively in 64-bit mode for some time now. The console, however has been forced to run in 32-bit mode. The reason for this is that in Windows, any 64-bit process can only load 64-bit dlls. You can’t mix and match 64-bit and 32-bit code.</p> <p>SQL Sentry was conceived when SQL Server 2000 was the dominant SQL Server version. As such we decided early on to support reading SQL Server Enterprise Manager registrations into the console using SQL-DMO. We also found we could (with some work) show Enterprise Manager property windows and dialogs using the SQL-NS library. Both of these libraries were COM libraries, and since SQL Server 2000 was written at a time when 32-bit was your only OS option, the COM libraries were 32-bit. Eventually Microsoft added support for 64-bit operating systems in SQL Server 2000, but the client tools, running in 32-bit mode anyway, had no need to get these updates.</p> <p>Because the console linked directly to these dlls to support reading registrations and showing SQL Server 2000 dialogs, the console was forced to run in 32-bit mode, lest it not be able to load the 32-bit dlls. This wasn’t a major issue to do, as it’s easy to flag an executable to run in x86 mode (vs. the default automatic detection mode for managed applications) by just setting that as a compilation option. It worked and that’s how SQL Sentry has been able to interoperate with SQL Server 2000 until now.</p> <p>In 4.2 we wanted to support reading SQL Server 2008 registrations. This proved to be quite an engineering task as we found that Microsoft changed many of the APIs used to read in this registration data. Because of this we decided to go back to the drawing board and reengineer the way we read in registration information. As stated previously, before we linked directly to the registration COM objects (for SQL Server 2000) and SMO assemblies (for 2005). For 4.2 we elected to use an intermediate layer. We abstracted all the functionality we needed into a set of interfaces that we could read/write to, and then created plugins, one for 2000, one for 2005, and one for 2008. That allowed us to independently manage all the plugins and their corresponding references and decouple their implementations from the console. It was an undertaking but it paid off, because we have a much better separation of code layers, and we also will be able to support the next version of SQL Server without any major work.</p> <p>Around the time when I’d looked at the feasibility of making the console work in 64-bit mode I quickly realized that doing so would require such a decoupling, because I had to get the 32-bit dlls out of the console process. It just so happens that the work done for 4.2 did just that.</p> <p>In 4.3 the default build will not have the 32-bit flag in the manifest, so it will launch using whatever architecture the processor/OS supports. The side effect of this is if you are using the SQL Sentry Console on a 64-bit system and running it in 64-bit mode, you will be unable to read in SQL Server 2000 registrations, because it will not load the 2000 plugin (if it did it wouldn’t work due to the 64-bit/32-bit process/dll interoperability issue). The workaround for this is that we’re also shipping an x86 SQL Sentry Console that is flagged to run in x86 mode. This console will only be installed on 64-bit operating systems. If you install SQL Sentry on a 64-bit OS starting with 4.3 you’ll see two executable shortcuts in the start menu:</p> <p>SQL Sentry Console and <br />SQL Sentry Console (x86)</p> <p>If you require interoperation with SQL Server Enterprise Manager registrations, you should run the x86 version, otherwise, run the regular SQL Sentry Console, which will run in 64-bit mode on a 64-bit OS.</p>Brooke Philpotthttp://www.blogger.com/profile/08943147081689036679noreply@blogger.com0tag:blogger.com,1999:blog-7109482435925565923.post-64025961583461490032009-01-06T16:56:00.001-05:002009-01-06T17:30:26.903-05:00Dictionary Replication<p>It is very common in programming to need to do a replication of data. In SQL Sentry when we pull objects from remote systems we need to figure out if they exist in our database. We index objects by specific keys, and then during the synchronization process use these keys and compare them to the remote objects keys to figure out what objects are new, what objects have been deleted, and what objects have changed. The details of everything we do are beyond the scope of this article, but I find myself doing enough of these dictionary replications that I decided to blog about it.</p> <p>Take the following scenario:<br />You have two dictionaries,</p> <p>Dictionary<K,VTarget> targetDictionary<br />and <br />Dictionary<K,VSource> sourceDictionary</p> <p>You want to in one call update targetDictionary with all the contents of sourceDictionary, and be able to generate callbacks for new entries, deleted entries, and changed entries. The value types are different, as you plan to map VSource to VTarget (more on that later), but they share a common key data type (we could later expand that to be different too if it suited us). It seems a bit overwhelming but it’s a perfect example of where generics can make your life a lot easier. Traditionally I’d find myself writing three loops. In the first loop I update changed items and add new items that are in the source but not in the target. In the second l find the keys that are in the target but not in the source. These are deleted items. I cant remove them yet though because I’m inside an enumerator and that would generate an error, so I use a temp collection then do one more loop at the end to remove them from the target.</p> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"> <div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> <span style="color: rgb(0, 128, 0);">// Initialize the collections</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> Dictionary<<span style="color: rgb(0, 0, 255);">int</span>, <span style="color: rgb(0, 0, 255);">string</span>> peopleByIDTarget = <span style="color: rgb(0, 0, 255);">new</span> Dictionary<<span style="color: rgb(0, 0, 255);">int</span>, <span style="color: rgb(0, 0, 255);">string</span>>();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> Dictionary<<span style="color: rgb(0, 0, 255);">int</span>, <span style="color: rgb(0, 0, 255);">string</span>> peopleByIDSource = <span style="color: rgb(0, 0, 255);">new</span> Dictionary<<span style="color: rgb(0, 0, 255);">int</span>, <span style="color: rgb(0, 0, 255);">string</span>>();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 5:</span> peopleByIDTarget.Add(1, <span style="color: rgb(0, 96, 128);">"Brooke"</span>);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 6:</span> peopleByIDTarget.Add(2, <span style="color: rgb(0, 96, 128);">"Tommy"</span>);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 7:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 8:</span> peopleByIDSource.Add(2, <span style="color: rgb(0, 96, 128);">"Rick"</span>);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 9:</span> peopleByIDSource.Add(3, <span style="color: rgb(0, 96, 128);">"Dom"</span>);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 10:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 11:</span> <span style="color: rgb(0, 128, 0);">// Loop through the source</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 12:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (KeyValuePair<<span style="color: rgb(0, 0, 255);">int</span>, <span style="color: rgb(0, 0, 255);">string</span>> sourceKeyValuePair <span style="color: rgb(0, 0, 255);">in</span> peopleByIDSource)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 13:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 14:</span> <span style="color: rgb(0, 0, 255);">string</span> existingName;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 15:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 16:</span> <span style="color: rgb(0, 0, 255);">if</span> (peopleByIDTarget.TryGetValue(sourceKeyValuePair.Key, <span style="color: rgb(0, 0, 255);">out</span> existingName))</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 17:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 18:</span> <span style="color: rgb(0, 128, 0);">// ID Exists. Change Name!</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 19:</span> peopleByIDTarget[sourceKeyValuePair.Key] = sourceKeyValuePair.Value;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 20:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 21:</span> <span style="color: rgb(0, 0, 255);">else</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 22:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 23:</span> <span style="color: rgb(0, 128, 0);">// ID doesn't exist, so add with name.</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 24:</span> peopleByIDTarget.Add(sourceKeyValuePair.Key, sourceKeyValuePair.Value);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 25:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 26:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 27:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 28:</span> <span style="color: rgb(0, 128, 0);">// Create a temp list to hold items we need to remove. You cant remove items</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 29:</span> <span style="color: rgb(0, 128, 0);">// while enumerating or you get an error.</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 30:</span> List<<span style="color: rgb(0, 0, 255);">int</span>> keysToRemove = <span style="color: rgb(0, 0, 255);">new</span> List<<span style="color: rgb(0, 0, 255);">int</span>>();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 31:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 32:</span> <span style="color: rgb(0, 128, 0);">// Loop through the target to see what items dont exist in the source</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 33:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (KeyValuePair<<span style="color: rgb(0, 0, 255);">int</span>, <span style="color: rgb(0, 0, 255);">string</span>> targetKeyValuePair <span style="color: rgb(0, 0, 255);">in</span> peopleByIDTarget)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 34:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 35:</span> <span style="color: rgb(0, 128, 0);">// The target item doesnt exist in the source so we must remove it.</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 36:</span> <span style="color: rgb(0, 128, 0);">// Add it to the removal list.</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 37:</span> <span style="color: rgb(0, 0, 255);">if</span> (!peopleByIDSource.ContainsKey(targetKeyValuePair.Key))</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 38:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 39:</span> keysToRemove.Add(targetKeyValuePair.Key);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 40:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 41:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 42:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 43:</span> <span style="color: rgb(0, 128, 0);">// Remove the keys we marked for removal</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 44:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (<span style="color: rgb(0, 0, 255);">int</span> key <span style="color: rgb(0, 0, 255);">in</span> keysToRemove)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 45:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 46:</span> peopleByIDTarget.Remove(key);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 47:</span> }</pre> </div></div><p>This works but it’s quite a bit of code, especially if this is happening with a lot of collections. I like to promote code reuse so the goal was to make this routine generic so that I could simply call:</p><p>peopleByIDTarget.Merge(peopleByIDSource);</p><p>Another thing the above example lacks is support for the callbacks I mentioned earlier. I’d like to know when an item is removed, added, or changed, and specify it in a easily defined way, like </p><p>peopleByIDTarget.Merge(peopleByIDSource, itemAddedCallback, itemChangedCallback, itemRemovedCallback)</p><p>and get the item that was removed, added, or changed.</p><p>It’s pretty straightforward to convert the above code into a generic method. The following is the most advanced version, supporting lots of options, callbacks, comparisons to see whether two values are the same (you may not always wish to fire the changed event if the instance of V didn’t have any properties that are different).</p><p>First we need to define some helper classes for the callbacks:</p> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> <span style="color: rgb(0, 128, 0);">/// Provides event arguments for items that are added to a dictionary.</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="K">The Key type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 5:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="V">The Value type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 6:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">class</span> DictionaryItemAddedEventArgs<K, V> : EventArgs</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 7:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 8:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 9:</span> <span style="color: rgb(0, 128, 0);">/// The Key</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 10:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 11:</span> <span style="color: rgb(0, 0, 255);">public</span> K Key { get; <span style="color: rgb(0, 0, 255);">private</span> set; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 12:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 13:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 14:</span> <span style="color: rgb(0, 128, 0);">/// The new value</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 15:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 16:</span> <span style="color: rgb(0, 0, 255);">public</span> V NewValue { get; <span style="color: rgb(0, 0, 255);">private</span> set; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 17:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 18:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 19:</span> <span style="color: rgb(0, 128, 0);">/// Creates a new DictionaryItemAddedEventArgs</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 20:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 21:</span> <span style="color: rgb(0, 128, 0);">/// <param name="key">The key</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 22:</span> <span style="color: rgb(0, 128, 0);">/// <param name="newValue">The new value</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 23:</span> <span style="color: rgb(0, 0, 255);">public</span> DictionaryItemAddedEventArgs(K key, V newValue)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 24:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 25:</span> <span style="color: rgb(0, 0, 255);">this</span>.Key = key;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 26:</span> <span style="color: rgb(0, 0, 255);">this</span>.NewValue = newValue;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 27:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 28:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 29:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 30:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 31:</span> <span style="color: rgb(0, 128, 0);">/// Provides event arguments for items that are changed in a dictionary.</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 32:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 33:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="K">The Key type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 34:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="V">The Value type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 35:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">class</span> DictionaryItemChangedEventArgs<K, V> : EventArgs</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 36:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 37:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 38:</span> <span style="color: rgb(0, 128, 0);">/// The Key</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 39:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 40:</span> <span style="color: rgb(0, 0, 255);">public</span> K Key{ get; <span style="color: rgb(0, 0, 255);">private</span> set; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 41:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 42:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 43:</span> <span style="color: rgb(0, 128, 0);">/// The previous value</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 44:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 45:</span> <span style="color: rgb(0, 0, 255);">public</span> V OldValue { get; <span style="color: rgb(0, 0, 255);">private</span> set; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 46:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 47:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 48:</span> <span style="color: rgb(0, 128, 0);">/// The new value</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 49:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 50:</span> <span style="color: rgb(0, 0, 255);">public</span> V NewValue { get; <span style="color: rgb(0, 0, 255);">private</span> set; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 51:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 52:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 53:</span> <span style="color: rgb(0, 128, 0);">/// Creates a new DictionaryItemChangedEventArgs</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 54:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 55:</span> <span style="color: rgb(0, 128, 0);">/// <param name="key">The key</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 56:</span> <span style="color: rgb(0, 128, 0);">/// <param name="oldValue">The previous value</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 57:</span> <span style="color: rgb(0, 128, 0);">/// <param name="newValue">The new value</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 58:</span> <span style="color: rgb(0, 0, 255);">public</span> DictionaryItemChangedEventArgs(K key, V oldValue, V newValue)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 59:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 60:</span> <span style="color: rgb(0, 0, 255);">this</span>.Key = key;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 61:</span> <span style="color: rgb(0, 0, 255);">this</span>.OldValue = oldValue;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 62:</span> <span style="color: rgb(0, 0, 255);">this</span>.NewValue = newValue;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 63:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 64:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 65:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 66:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 67:</span> <span style="color: rgb(0, 128, 0);">/// Provides event arguments for items that are deleted from a dictionary.</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 68:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 69:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="K">The Key type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 70:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="V">The Value type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 71:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">class</span> DictionaryItemDeletedEventArgs<K, V> : EventArgs</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 72:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 73:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 74:</span> <span style="color: rgb(0, 128, 0);">/// The Key</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 75:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 76:</span> <span style="color: rgb(0, 0, 255);">public</span> K Key { get; <span style="color: rgb(0, 0, 255);">private</span> set; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 77:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 78:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 79:</span> <span style="color: rgb(0, 128, 0);">/// The previous value</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 80:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 81:</span> <span style="color: rgb(0, 0, 255);">public</span> V OldValue { get; <span style="color: rgb(0, 0, 255);">private</span> set; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 82:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 83:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 84:</span> <span style="color: rgb(0, 128, 0);">/// Creates a new DictionaryItemDeletedEventArgs</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 85:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 86:</span> <span style="color: rgb(0, 128, 0);">/// <param name="key">The key</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 87:</span> <span style="color: rgb(0, 128, 0);">/// <param name="oldValue">The previous value</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 88:</span> <span style="color: rgb(0, 0, 255);">public</span> DictionaryItemDeletedEventArgs(K key, V oldValue)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 89:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 90:</span> <span style="color: rgb(0, 0, 255);">this</span>.Key = key;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 91:</span> <span style="color: rgb(0, 0, 255);">this</span>.OldValue = oldValue;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 92:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 93:</span> }</pre> </div></div><p>Then we can get to the actual dictionary extensions class. The primary work starts on line 180 and I've included a couple other helper extensions I added for other uses:</p> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> <span style="color: rgb(0, 128, 0);">/// Provides extention methods to the dictionary class</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">class</span> DictionaryExtensions</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 5:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 6:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 7:</span> <span style="color: rgb(0, 128, 0);">/// Creates a new Dictionary with the key and value of the current dictionary reversed.</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 8:</span> <span style="color: rgb(0, 128, 0);">/// This method should be not used when duplicate values are expected because collisions will occur.</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 9:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 10:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="K">The Key type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 11:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="V">The Value type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 12:</span> <span style="color: rgb(0, 128, 0);">/// <param name="dictionary">The dictionary to use</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 13:</span> <span style="color: rgb(0, 128, 0);">/// <returns>A Dictionary with the keys and values of the current dictionary reversed</returns></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 14:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> Dictionary<V, K> CreateDictionaryOfValueAndKey<K, V>(<span style="color: rgb(0, 0, 255);">this</span> Dictionary<K, V> dictionary)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 15:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 16:</span> Dictionary<V, K> result = <span style="color: rgb(0, 0, 255);">new</span> Dictionary<V,K>();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 17:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (KeyValuePair<K, V> keyValuePair <span style="color: rgb(0, 0, 255);">in</span> dictionary)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 18:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 19:</span> result.Add(keyValuePair.Value, keyValuePair.Key);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 20:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 21:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 22:</span> <span style="color: rgb(0, 0, 255);">return</span> result;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 23:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 24:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 25:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 26:</span> <span style="color: rgb(0, 128, 0);">/// Creates a new MultiDictionary with the key and value of the current dictionary reversed.</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 27:</span> <span style="color: rgb(0, 128, 0);">/// This method should be used when duplicate values are expected.</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 28:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 29:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="K">The Key type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 30:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="V">The Value type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 31:</span> <span style="color: rgb(0, 128, 0);">/// <param name="dictionary">The dictionary to use</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 32:</span> <span style="color: rgb(0, 128, 0);">/// <returns>A MultiDictionary with the keys and values of the current dictionary reversed</returns></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 33:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> MultiDictionary<V, K> CreateMultiDictionaryOfValueAndKey<K, V>(<span style="color: rgb(0, 0, 255);">this</span> Dictionary<K, V> dictionary)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 34:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 35:</span> MultiDictionary<V, K> result = <span style="color: rgb(0, 0, 255);">new</span> MultiDictionary<V, K>();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 36:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (KeyValuePair<K, V> keyValuePair <span style="color: rgb(0, 0, 255);">in</span> dictionary)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 37:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 38:</span> result.Add(keyValuePair.Value, keyValuePair.Key);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 39:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 40:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 41:</span> <span style="color: rgb(0, 0, 255);">return</span> result;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 42:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 43:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 44:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 45:</span> <span style="color: rgb(0, 128, 0);">/// Merges the targetDictionary with the sourceDictionary, deleting items that arent in sourceDictionary, </span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 46:</span> <span style="color: rgb(0, 128, 0);">/// adding items that are in sourceDictionary but not in the targetDictionary, and updating items that are in both, </span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 47:</span> <span style="color: rgb(0, 128, 0);">/// setting them to the value in sourceDictionary</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 48:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 49:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="K">The Key type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 50:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="V">The Value type of the source and target dictionaries</typeparam> </span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 51:</span> <span style="color: rgb(0, 128, 0);">/// <param name="targetDictionary">The current dictionary to merge entries into</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 52:</span> <span style="color: rgb(0, 128, 0);">/// <param name="sourceDictionary">The new dictionary with the most recent data</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 53:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">void</span> Merge<K, V>(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 54:</span> <span style="color: rgb(0, 0, 255);">this</span> Dictionary<K, V> targetDictionary,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 55:</span> Dictionary<K, V> sourceDictionary)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 56:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 57:</span> Merge(targetDictionary, sourceDictionary, <span style="color: rgb(0, 0, 255);">null</span>, <span style="color: rgb(0, 0, 255);">null</span>, <span style="color: rgb(0, 0, 255);">null</span>, <span style="color: rgb(0, 0, 255);">null</span>, <span style="color: rgb(0, 0, 255);">null</span>);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 58:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 59:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 60:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 61:</span> <span style="color: rgb(0, 128, 0);">/// Merges the targetDictionary with the sourceDictionary, deleting items that arent in sourceDictionary, </span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 62:</span> <span style="color: rgb(0, 128, 0);">/// adding items that are in sourceDictionary but not in the targetDictionary, and updating items that are in both, </span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 63:</span> <span style="color: rgb(0, 128, 0);">/// setting them to the value in sourceDictionary</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 64:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 65:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="K">The Key type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 66:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="VTarget">The Value type of the target dictionary</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 67:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="VSource">The Value type of the source dictionary</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 68:</span> <span style="color: rgb(0, 128, 0);">/// <param name="targetDictionary">The current dictionary to merge entries into</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 69:</span> <span style="color: rgb(0, 128, 0);">/// <param name="sourceDictionary">The new dictionary with the most recent data</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 70:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">void</span> Merge<K, VTarget, VSource>(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 71:</span> <span style="color: rgb(0, 0, 255);">this</span> Dictionary<K, VTarget> targetDictionary,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 72:</span> Dictionary<K, VSource> sourceDictionary)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 73:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 74:</span> Merge(targetDictionary, sourceDictionary, <span style="color: rgb(0, 0, 255);">null</span>, <span style="color: rgb(0, 0, 255);">null</span>, <span style="color: rgb(0, 0, 255);">null</span>, <span style="color: rgb(0, 0, 255);">null</span>, <span style="color: rgb(0, 0, 255);">null</span>);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 75:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 76:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 77:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 78:</span> <span style="color: rgb(0, 128, 0);">/// Merges the targetDictionary with the sourceDictionary, deleting items that arent in sourceDictionary, </span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 79:</span> <span style="color: rgb(0, 128, 0);">/// adding items that are in sourceDictionary but not in the targetDictionary, and updating items that are in both, </span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 80:</span> <span style="color: rgb(0, 128, 0);">/// setting them to the value in sourceDictionary</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 81:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 82:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="K">The Key type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 83:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="V">The Value type of the source and target dictionaries</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 84:</span> <span style="color: rgb(0, 128, 0);">/// <param name="targetDictionary">The current dictionary to merge entries into</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 85:</span> <span style="color: rgb(0, 128, 0);">/// <param name="sourceDictionary">The new dictionary with the most recent data</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 86:</span> <span style="color: rgb(0, 128, 0);">/// <param name="valueUpdater">The action to use to update values that share the same key</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 87:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">void</span> Merge<K, V>(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 88:</span> <span style="color: rgb(0, 0, 255);">this</span> Dictionary<K, V> targetDictionary,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 89:</span> Dictionary<K, V> sourceDictionary,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 90:</span> Func<V, V, <span style="color: rgb(0, 0, 255);">bool</span>> valueUpdater)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 91:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 92:</span> Func<V, V> valueMapper = x => x;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 93:</span> Merge(targetDictionary, sourceDictionary, valueMapper, valueUpdater, <span style="color: rgb(0, 0, 255);">null</span>, <span style="color: rgb(0, 0, 255);">null</span>, <span style="color: rgb(0, 0, 255);">null</span>);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 94:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 95:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 96:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 97:</span> <span style="color: rgb(0, 128, 0);">/// Merges the targetDictionary with the sourceDictionary, deleting items that arent in sourceDictionary, </span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 98:</span> <span style="color: rgb(0, 128, 0);">/// adding items that are in sourceDictionary but not in the targetDictionary, and updating items that are in both, </span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 99:</span> <span style="color: rgb(0, 128, 0);">/// setting them to the value in sourceDictionary</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 100:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 101:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="K">The Key type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 102:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="VTarget">The Value type of the target dictionary</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 103:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="VSource">The Value type of the source dictionary</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 104:</span> <span style="color: rgb(0, 128, 0);">/// <param name="targetDictionary">The current dictionary to merge entries into</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 105:</span> <span style="color: rgb(0, 128, 0);">/// <param name="sourceDictionary">The new dictionary with the most recent data</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 106:</span> <span style="color: rgb(0, 128, 0);">/// <param name="valueMapper">The transform to convert VSource to VTarget</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 107:</span> <span style="color: rgb(0, 128, 0);">/// <param name="valueUpdater">The action to use to update values that share the same key</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 108:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">void</span> Merge<K, VTarget, VSource>(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 109:</span> <span style="color: rgb(0, 0, 255);">this</span> Dictionary<K, VTarget> targetDictionary,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 110:</span> Dictionary<K, VSource> sourceDictionary,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 111:</span> Func<VSource, VTarget> valueMapper,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 112:</span> Func<VTarget, VTarget, <span style="color: rgb(0, 0, 255);">bool</span>> valueUpdater)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 113:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 114:</span> Merge(targetDictionary, sourceDictionary, valueMapper, valueUpdater, <span style="color: rgb(0, 0, 255);">null</span>, <span style="color: rgb(0, 0, 255);">null</span>, <span style="color: rgb(0, 0, 255);">null</span>);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 115:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 116:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 117:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 118:</span> <span style="color: rgb(0, 128, 0);">/// Merges the targetDictionary with the sourceDictionary, deleting items that arent in sourceDictionary, </span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 119:</span> <span style="color: rgb(0, 128, 0);">/// adding items that are in sourceDictionary but not in the targetDictionary, and updating items that are in both, </span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 120:</span> <span style="color: rgb(0, 128, 0);">/// setting them to the value in sourceDictionary</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 121:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 122:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="K">The Key type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 123:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="V">The Value type of the source and target dictionaries</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 124:</span> <span style="color: rgb(0, 128, 0);">/// <param name="targetDictionary">The current dictionary to merge entries into</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 125:</span> <span style="color: rgb(0, 128, 0);">/// <param name="sourceDictionary">The new dictionary with the most recent data</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 126:</span> <span style="color: rgb(0, 128, 0);">/// <param name="itemAddedEventHandler">The event to fire for items that were added</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 127:</span> <span style="color: rgb(0, 128, 0);">/// <param name="itemChangedEventHandler">The event to fire for items that were changed</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 128:</span> <span style="color: rgb(0, 128, 0);">/// <param name="itemDeletedEventHandler">The event to fire for items that were deleted</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 129:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">void</span> Merge<K, V>(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 130:</span> <span style="color: rgb(0, 0, 255);">this</span> Dictionary<K, V> targetDictionary,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 131:</span> Dictionary<K, V> sourceDictionary,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 132:</span> EventHandler<DictionaryItemAddedEventArgs<K, V>> itemAddedEventHandler,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 133:</span> EventHandler<DictionaryItemChangedEventArgs<K, V>> itemChangedEventHandler,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 134:</span> EventHandler<DictionaryItemDeletedEventArgs<K, V>> itemDeletedEventHandler)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 135:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 136:</span> Func<V, V> valueMapper = x => x;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 137:</span> Merge(targetDictionary, sourceDictionary, valueMapper, <span style="color: rgb(0, 0, 255);">null</span>, itemAddedEventHandler, itemChangedEventHandler, itemDeletedEventHandler);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 138:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 139:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 140:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 141:</span> <span style="color: rgb(0, 128, 0);">/// Merges the targetDictionary with the sourceDictionary, deleting items that arent in sourceDictionary, </span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 142:</span> <span style="color: rgb(0, 128, 0);">/// adding items that are in sourceDictionary but not in the targetDictionary, and updating items that are in both, </span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 143:</span> <span style="color: rgb(0, 128, 0);">/// setting them to the value in sourceDictionary</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 144:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 145:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="K">The Key type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 146:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="VTarget">The Value type of the target dictionary</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 147:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="VSource">The Value type of the source dictionary</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 148:</span> <span style="color: rgb(0, 128, 0);">/// <param name="targetDictionary">The current dictionary to merge entries into</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 149:</span> <span style="color: rgb(0, 128, 0);">/// <param name="sourceDictionary">The new dictionary with the most recent data</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 150:</span> <span style="color: rgb(0, 128, 0);">/// <param name="valueMapper">The transform to convert VSource to VTarget</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 151:</span> <span style="color: rgb(0, 128, 0);">/// <param name="itemAddedEventHandler">The event to fire for items that were added</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 152:</span> <span style="color: rgb(0, 128, 0);">/// <param name="itemChangedEventHandler">The event to fire for items that were changed</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 153:</span> <span style="color: rgb(0, 128, 0);">/// <param name="itemDeletedEventHandler">The event to fire for items that were deleted</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 154:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">void</span> Merge<K, VTarget, VSource>(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 155:</span> <span style="color: rgb(0, 0, 255);">this</span> Dictionary<K, VTarget> targetDictionary,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 156:</span> Dictionary<K, VSource> sourceDictionary,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 157:</span> Func<VSource, VTarget> valueMapper,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 158:</span> EventHandler<DictionaryItemAddedEventArgs<K, VTarget>> itemAddedEventHandler,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 159:</span> EventHandler<DictionaryItemChangedEventArgs<K, VTarget>> itemChangedEventHandler,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 160:</span> EventHandler<DictionaryItemDeletedEventArgs<K, VTarget>> itemDeletedEventHandler)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 161:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 162:</span> Merge(targetDictionary, sourceDictionary, valueMapper, <span style="color: rgb(0, 0, 255);">null</span>, itemAddedEventHandler, itemChangedEventHandler, itemDeletedEventHandler);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 163:</span> } </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 164:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 165:</span> <span style="color: rgb(0, 128, 0);">/// <summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 166:</span> <span style="color: rgb(0, 128, 0);">/// Merges the targetDictionary with the sourceDictionary, deleting items that arent in sourceDictionary, </span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 167:</span> <span style="color: rgb(0, 128, 0);">/// adding items that are in sourceDictionary but not in the targetDictionary, and updating items that are in both, </span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 168:</span> <span style="color: rgb(0, 128, 0);">/// setting them to the value in sourceDictionary</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 169:</span> <span style="color: rgb(0, 128, 0);">/// </summary></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 170:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="K">The Key type</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 171:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="VTarget">The Value type of the target dictionary</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 172:</span> <span style="color: rgb(0, 128, 0);">/// <typeparam name="VSource">The Value type of the source dictionary</typeparam></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 173:</span> <span style="color: rgb(0, 128, 0);">/// <param name="targetDictionary">The current dictionary to merge entries into</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 174:</span> <span style="color: rgb(0, 128, 0);">/// <param name="sourceDictionary">The new dictionary with the most recent data</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 175:</span> <span style="color: rgb(0, 128, 0);">/// <param name="valueMapper">The transform to convert VSource to VTarget</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 176:</span> <span style="color: rgb(0, 128, 0);">/// <param name="valueUpdater">The action to use to update values that share the same key</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 177:</span> <span style="color: rgb(0, 128, 0);">/// <param name="itemAddedEventHandler">The event to fire for items that were added</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 178:</span> <span style="color: rgb(0, 128, 0);">/// <param name="itemChangedEventHandler">The event to fire for items that were changed</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 179:</span> <span style="color: rgb(0, 128, 0);">/// <param name="itemDeletedEventHandler">The event to fire for items that were deleted</param></span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 180:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">void</span> Merge<K, VTarget, VSource>(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 181:</span> <span style="color: rgb(0, 0, 255);">this</span> Dictionary<K, VTarget> targetDictionary,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 182:</span> Dictionary<K, VSource> sourceDictionary,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 183:</span> Func<VSource, VTarget> valueMapper,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 184:</span> Func<VTarget, VTarget, <span style="color: rgb(0, 0, 255);">bool</span>> valueUpdater,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 185:</span> EventHandler<DictionaryItemAddedEventArgs<K, VTarget>> itemAddedEventHandler,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 186:</span> EventHandler<DictionaryItemChangedEventArgs<K, VTarget>> itemChangedEventHandler,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 187:</span> EventHandler<DictionaryItemDeletedEventArgs<K, VTarget>> itemDeletedEventHandler)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 188:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 189:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (var keyValuePair <span style="color: rgb(0, 0, 255);">in</span> sourceDictionary)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 190:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 191:</span> VTarget newValue = valueMapper(keyValuePair.Value);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 192:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 193:</span> VTarget oldValue;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 194:</span> <span style="color: rgb(0, 0, 255);">if</span> (targetDictionary.TryGetValue(keyValuePair.Key, <span style="color: rgb(0, 0, 255);">out</span> oldValue))</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 195:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 196:</span> <span style="color: rgb(0, 0, 255);">bool</span> changed = <span style="color: rgb(0, 0, 255);">true</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 197:</span> <span style="color: rgb(0, 0, 255);">if</span> (valueUpdater == <span style="color: rgb(0, 0, 255);">null</span>)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 198:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 199:</span> targetDictionary[keyValuePair.Key] = newValue;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 200:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 201:</span> <span style="color: rgb(0, 0, 255);">else</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 202:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 203:</span> changed = valueUpdater(oldValue, newValue);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 204:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 205:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 206:</span> <span style="color: rgb(0, 0, 255);">if</span> (itemChangedEventHandler != <span style="color: rgb(0, 0, 255);">null</span> && changed)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 207:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 208:</span> itemChangedEventHandler(targetDictionary, <span style="color: rgb(0, 0, 255);">new</span> DictionaryItemChangedEventArgs<K, VTarget>(keyValuePair.Key, oldValue, newValue));</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 209:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 210:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 211:</span> <span style="color: rgb(0, 0, 255);">else</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 212:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 213:</span> targetDictionary.Add(keyValuePair.Key, newValue);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 214:</span> <span style="color: rgb(0, 0, 255);">if</span> (itemAddedEventHandler != <span style="color: rgb(0, 0, 255);">null</span>)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 215:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 216:</span> itemAddedEventHandler(targetDictionary, <span style="color: rgb(0, 0, 255);">new</span> DictionaryItemAddedEventArgs<K, VTarget>(keyValuePair.Key, newValue));</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 217:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 218:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 219:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 220:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 221:</span> List<KeyValuePair<K, VTarget>> itemsToDelete = <span style="color: rgb(0, 0, 255);">new</span> List<KeyValuePair<K, VTarget>>();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 222:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (var keyValuePair <span style="color: rgb(0, 0, 255);">in</span> targetDictionary)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 223:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 224:</span> <span style="color: rgb(0, 0, 255);">if</span> (!sourceDictionary.ContainsKey(keyValuePair.Key))</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 225:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 226:</span> itemsToDelete.Add(keyValuePair);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 227:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 228:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 229:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 230:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (var keyValuePair <span style="color: rgb(0, 0, 255);">in</span> itemsToDelete)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 231:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 232:</span> targetDictionary.Remove(keyValuePair.Key);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 233:</span> <span style="color: rgb(0, 0, 255);">if</span> (itemDeletedEventHandler != <span style="color: rgb(0, 0, 255);">null</span>)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 234:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 235:</span> itemDeletedEventHandler(targetDictionary, <span style="color: rgb(0, 0, 255);">new</span> DictionaryItemDeletedEventArgs<K, VTarget>(keyValuePair.Key, keyValuePair.Value));</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 236:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 237:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 238:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 239:</span> }</pre> </div></div><p></p><p></p><p>It’s essentially the original code, just made generic with the callbacks included. There are some additional Func<> delegates. valueMapper is used to transform the source value type to the target value type if they are different. Note there are overloads that do not require this and they just use a simple x=>x mapping. Also, there is a valueUpdater delegate as well. It is used to compare two values to see if they are really the same, which is useful if the value type is a class with properties and you want to see if those have changed prior to calling the changed callback.</p><p>Taking the initial example we can now do this:</p><div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> <span style="color: rgb(0, 0, 255);">int</span> countRemoved = 0;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> <span style="color: rgb(0, 0, 255);">int</span> countAdded = 0;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> <span style="color: rgb(0, 0, 255);">int</span> countChanged = 0;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 5:</span> peopleByIDTarget.Merge(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 6:</span> peopleByIDSource,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 7:</span> (dictionary, itemAddedArgs) =></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 8:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 9:</span> countAdded++;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 10:</span> System.Diagnostics.Debug.WriteLine(<span style="color: rgb(0, 96, 128);">"Item "</span> + itemAddedArgs.NewValue + <span style="color: rgb(0, 96, 128);">" Added"</span>);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 11:</span> },</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 12:</span> (dictionary, itemChangedArgs) =></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 13:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 14:</span> countChanged++;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 15:</span> System.Diagnostics.Debug.WriteLine(<span style="color: rgb(0, 96, 128);">"Item "</span> + itemChangedArgs.OldValue + <span style="color: rgb(0, 96, 128);">" changed to "</span> + itemChangedArgs.NewValue);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 16:</span> },</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 17:</span> (dictionary, itemRemovedArgs) =></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 18:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 19:</span> countRemoved++;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 20:</span> System.Diagnostics.Debug.WriteLine(<span style="color: rgb(0, 96, 128);">"Item "</span> + itemRemovedArgs.OldValue + <span style="color: rgb(0, 96, 128);">" Removed"</span>);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 21:</span> });</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 22:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 23:</span> System.Diagnostics.Debug.WriteLine(countAdded.ToString() + <span style="color: rgb(0, 96, 128);">" Items Added"</span>);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 24:</span> System.Diagnostics.Debug.WriteLine(countChanged.ToString() + <span style="color: rgb(0, 96, 128);">" Items Changed"</span>);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 25:</span> System.Diagnostics.Debug.WriteLine(countRemoved.ToString() + <span style="color: rgb(0, 96, 128);">" Items Removed"</span>);</pre> </div></div><br />Generics combined with closures allows for some very rapid development.Brooke Philpotthttp://www.blogger.com/profile/08943147081689036679noreply@blogger.com0tag:blogger.com,1999:blog-7109482435925565923.post-30619179163508275532008-10-17T16:34:00.001-04:002008-11-24T23:12:22.146-05:00Mapping Parents to Children Using Anonymous Types and LINQ<p>After writing my last post I spent some time thinking about certain places where the DeepEnumerator class helped me, and one of the uses that I came across was based on a particular challenge. I had a class that represented the tree structure that I talked about in my last post, namely it adhered to the following principle:</p> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"> <div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> <span style="color: rgb(0, 0, 255);">class</span> T</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> IEnumerable<T> Children { get; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> }</pre> </div></div><p></p><p>What I discovered is that it’s fairly common to have a situation where the parent defines it’s children in the aforementioned manner, but often in such cases, the children do not define their parents. What I wanted to do is to handle this case by creating a new class that holds the parent and the child and do it in a generic way.</p><p>For the purpose of illustrating anonymous types let’s do it first with anonymous types. Note: The following example uses LINQ for terseness and expressiveness, but it’s not required.</p><p>First, given the aforementioned class T, let’s define the anonymous type, given an instance of T called parent.</p><div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> <span style="color: rgb(0, 128, 0);">// assume parent which is the top most</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> <span style="color: rgb(0, 128, 0);">// element in the tree is defined</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> T parent = <span style="color: rgb(0, 0, 255);">new</span> T();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> var root = <span style="color: rgb(0, 0, 255);">new</span> {Parent=<span style="color: rgb(0, 0, 255);">default</span>(T), Element = parent};</pre> </div></div><p>This code may look odd but all we really are doing here is defining the concept of a root, and a root is an item that has no parent. We use default(T) to define the type. To enumerate, we know we want to enumerate starting with root, which internally represents a tuple of a parent and child, but the challenge is mapping root to IEnumerable<AnonymousType> where anonymous type is the type of root that we just defined.</p><p>To do so let’s use linq:</p><div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> elementAndParent =></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> var query =</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> from child <span style="color: rgb(0, 0, 255);">in</span> elementAndParent.Element.Children</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 5:</span> select <span style="color: rgb(0, 0, 255);">new</span> { Parent = elementAndParent.Element, Element = child };</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 6:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 7:</span> <span style="color: rgb(0, 0, 255);">return</span> query;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 8:</span> }</pre> </div></div><p>All this does is it takes the elementAndParent and maps it to a query that takes all the children under elementAndParent.Element(which is really the element that we are using currently on the tree) and returns a new anonymous type with that child as Element, and the current element as Parent.</p><p>Let’s look at it in the full context. Note I’ve defined our cute dog Kadi here as a person. Call it artistic license:</p><div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">class</span> Person</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> <span style="color: rgb(0, 0, 255);">private</span> List<Person> _Children = <span style="color: rgb(0, 0, 255);">new</span> List<Person>();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 5:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">int</span> Age { get; set; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 6:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">string</span> FirstName { get; set; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 7:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">string</span> LastName { get; set; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 8:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 9:</span> <span style="color: rgb(0, 0, 255);">public</span> List<Person> Children</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 10:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 11:</span> get { <span style="color: rgb(0, 0, 255);">return</span> _Children; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 12:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 13:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 14:</span> <span style="color: rgb(0, 0, 255);">private</span> <span style="color: rgb(0, 0, 255);">void</span> TestParents()</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 15:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 16:</span> Person parent = <span style="color: rgb(0, 0, 255);">new</span> Person();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 17:</span> parent.FirstName = <span style="color: rgb(0, 96, 128);">"Bob"</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 18:</span> parent.LastName = <span style="color: rgb(0, 96, 128);">"Philpott"</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 19:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 20:</span> Person child1 = <span style="color: rgb(0, 0, 255);">new</span> Person();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 21:</span> child1.FirstName = <span style="color: rgb(0, 96, 128);">"Brooke"</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 22:</span> child1.LastName = <span style="color: rgb(0, 96, 128);">"Philpott"</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 23:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 24:</span> Person child2 = <span style="color: rgb(0, 0, 255);">new</span> Person();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 25:</span> child2.FirstName = <span style="color: rgb(0, 96, 128);">"Stephen"</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 26:</span> child2.LastName = <span style="color: rgb(0, 96, 128);">"Philpott"</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 27:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 28:</span> Person pet1 = <span style="color: rgb(0, 0, 255);">new</span> Person();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 29:</span> pet1.FirstName = <span style="color: rgb(0, 96, 128);">"Kadi"</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 30:</span> pet1.LastName = <span style="color: rgb(0, 96, 128);">"Philpott"</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 31:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 32:</span> parent.Children.Add(child1);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 33:</span> parent.Children.Add(child2);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 34:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 35:</span> child1.Children.Add(pet1);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 36:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 37:</span> var root = <span style="color: rgb(0, 0, 255);">new</span> { Parent = <span style="color: rgb(0, 0, 255);">default</span>(Person), Element = parent };</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 38:</span> var allElementAndParents =</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 39:</span> Intercerve.Collections.Generic.DeepEnumerator.Enumerate(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 40:</span> root,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 41:</span> elementAndParent =></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 42:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 43:</span> var query =</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 44:</span> from child <span style="color: rgb(0, 0, 255);">in</span> elementAndParent.Element.Children</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 45:</span> select <span style="color: rgb(0, 0, 255);">new</span> { Parent = elementAndParent.Element, Element = child };</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 46:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 47:</span> <span style="color: rgb(0, 0, 255);">return</span> query;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 48:</span> });</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 49:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 50:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (var elementAndParent <span style="color: rgb(0, 0, 255);">in</span> allElementAndParents)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 51:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 52:</span> <span style="color: rgb(0, 0, 255);">if</span> (elementAndParent.Parent == <span style="color: rgb(0, 0, 255);">null</span>)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 53:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 54:</span> <span style="color: rgb(0, 0, 255);">continue</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 55:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 56:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 57:</span> <span style="color: rgb(0, 0, 255);">string</span> message = <span style="color: rgb(0, 0, 255);">string</span>.Format(<span style="color: rgb(0, 96, 128);">"{0} is the parent of {1}"</span>, elementAndParent.Parent.FirstName, elementAndParent.Element.FirstName);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 58:</span> System.Diagnostics.Debug.WriteLine(message);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 59:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 60:</span> }</pre> </div></div><p></p><p></p><p>Note I filtered out entries that don’t have parents, as those are roots and I don’t really care about them.</p><p>The only drawback to this approach is that anonymous types have to be local in scope, which prevents me from reusing this code (obviously not ideal). To fix this let’s declare the anonymous type as a real type:</p><div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> <span style="color: rgb(0, 0, 255);">class</span> ElementAndParent<T></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> <span style="color: rgb(0, 0, 255);">public</span> T Element { get; set; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> <span style="color: rgb(0, 0, 255);">public</span> T Parent { get; set; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 5:</span> }</pre> </div></div><p>Once we have this helper class we can define a function like so:</p><div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> <span style="color: rgb(0, 0, 255);">private</span> <span style="color: rgb(0, 0, 255);">static</span> IEnumerable<ElementAndParent<T>> GetElementsWithParentsDeep<T>(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> T parent, </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> Func<T, IEnumerable<T>> childMappingFunction)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 5:</span> var root = <span style="color: rgb(0, 0, 255);">new</span> ElementAndParent<T> { Parent = <span style="color: rgb(0, 0, 255);">default</span>(T), Element = parent };</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 6:</span> var allElementAndParents =</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 7:</span> Intercerve.Collections.Generic.DeepEnumerator.Enumerate(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 8:</span> root,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 9:</span> elementAndParent =></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 10:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 11:</span> var query =</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 12:</span> from child <span style="color: rgb(0, 0, 255);">in</span> childMappingFunction(elementAndParent.Element)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 13:</span> select <span style="color: rgb(0, 0, 255);">new</span> ElementAndParent<T> { Parent = elementAndParent.Element, Element = child };</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 14:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 15:</span> <span style="color: rgb(0, 0, 255);">return</span> query;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 16:</span> })</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 17:</span> .Where(item=>item.Parent != <span style="color: rgb(0, 0, 255);">null</span>);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 18:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 19:</span> <span style="color: rgb(0, 0, 255);">return</span> allElementAndParents;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 20:</span> }</pre> </div></div><span style="font-size:85%;"> <p>What if we wanted to be able to walk all the way up the parents from the current node. Pretty easy actually. We just make a couple modifications. First let us define a class:</p><div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> <span style="color: rgb(0, 0, 255);">private</span> <span style="color: rgb(0, 0, 255);">class</span> ElementAndParentExtended<T></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> <span style="color: rgb(0, 0, 255);">public</span> T Element { get; set; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> <span style="color: rgb(0, 0, 255);">public</span> ElementAndParentExtended<T> Parent { get; set; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 5:</span> }</pre> </div> </div> <p>This class basically makes parent the same type as the type itself, allowing us to get the parent’s parent. We can then modify the enumeration like so:<br /></p></span><div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> <span style="color: rgb(0, 0, 255);">private</span> <span style="color: rgb(0, 0, 255);">static</span> IEnumerable<ElementAndParent<T>> GetElementsWithParentsDeep<T>(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> T parent, </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> Func<T, IEnumerable<T>> childMappingFunction)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 5:</span> var root = <span style="color: rgb(0, 0, 255);">new</span> ElementAndParent<T> { Parent = <span style="color: rgb(0, 0, 255);">default</span>(T), Element = parent };</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 6:</span> var allElementAndParents =</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 7:</span> Intercerve.Collections.Generic.DeepEnumerator.Enumerate(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 8:</span> root,</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 9:</span> elementAndParent =></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 10:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 11:</span> var query =</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 12:</span> from child <span style="color: rgb(0, 0, 255);">in</span> childMappingFunction(elementAndParent.Element)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 13:</span> select <span style="color: rgb(0, 0, 255);">new</span> ElementAndParent<T> { Parent = elementAndParent.Element, Element = child };</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 14:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 15:</span> <span style="color: rgb(0, 0, 255);">return</span> query;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 16:</span> })</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 17:</span> .Where(item=>item.Parent != <span style="color: rgb(0, 0, 255);">null</span>);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 18:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 19:</span> <span style="color: rgb(0, 0, 255);">return</span> allElementAndParents;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 20:</span> }</pre> </div></div><p>To test, let’s make a new method:</p><div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> <span style="color: rgb(0, 0, 255);">private</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">void</span> TestParents2()</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> Person parent = <span style="color: rgb(0, 0, 255);">new</span> Person();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> parent.FirstName = <span style="color: rgb(0, 96, 128);">"Bob"</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 5:</span> parent.LastName = <span style="color: rgb(0, 96, 128);">"Philpott"</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 6:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 7:</span> Person child1 = <span style="color: rgb(0, 0, 255);">new</span> Person();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 8:</span> child1.FirstName = <span style="color: rgb(0, 96, 128);">"Brooke"</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 9:</span> child1.LastName = <span style="color: rgb(0, 96, 128);">"Philpott"</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 10:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 11:</span> Person child2 = <span style="color: rgb(0, 0, 255);">new</span> Person();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 12:</span> child2.FirstName = <span style="color: rgb(0, 96, 128);">"Stephen"</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 13:</span> child2.LastName = <span style="color: rgb(0, 96, 128);">"Philpott"</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 14:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 15:</span> Person pet1 = <span style="color: rgb(0, 0, 255);">new</span> Person();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 16:</span> pet1.FirstName = <span style="color: rgb(0, 96, 128);">"Kadi"</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 17:</span> pet1.LastName = <span style="color: rgb(0, 96, 128);">"Philpott"</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 18:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 19:</span> parent.Children.Add(child1);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 20:</span> parent.Children.Add(child2);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 21:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 22:</span> child1.Children.Add(pet1);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 23:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 24:</span> var parentsExtended = GetElementsWithParentsExtendedDeep(parent, item => item.Children);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 25:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (var item <span style="color: rgb(0, 0, 255);">in</span> parentsExtended)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 26:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 27:</span> <span style="color: rgb(0, 0, 255);">if</span> (item.Parent == <span style="color: rgb(0, 0, 255);">null</span>)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 28:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 29:</span> <span style="color: rgb(0, 0, 255);">continue</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 30:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 31:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 32:</span> StringBuilder message = <span style="color: rgb(0, 0, 255);">new</span> StringBuilder(item.Element.FirstName);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 33:</span> var itemParent = item.Parent;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 34:</span> <span style="color: rgb(0, 0, 255);">while</span> (itemParent != <span style="color: rgb(0, 0, 255);">null</span>)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 35:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 36:</span> message.Append(<span style="color: rgb(0, 96, 128);">" is the child of "</span> + itemParent.Element.FirstName);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 37:</span> itemParent = itemParent.Parent;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 38:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 39:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 40:</span> System.Diagnostics.Debug.WriteLine(message);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 41:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 42:</span> }</pre> </div></div><p>If you run the method you’ll see that each element can now walk up it’s hierarchy to get it’s ancestry.</p><p>These methods could be extended to support all the options that the deep enumerator does, but I’ve not done so in the interest of brevity. Note I also could have used the Tuple class for this, but I chose to create my own for clarity.</p>Brooke Philpotthttp://www.blogger.com/profile/08943147081689036679noreply@blogger.com0tag:blogger.com,1999:blog-7109482435925565923.post-78183823918720857782008-10-08T18:29:00.000-04:002008-10-09T12:59:52.974-04:00Deep enumerationOver the course of my programming career I've found myself working with tree data structures quite a bit. There are many examples of APIs that use trees, like tree controls, directories of a file system, etc. It is often desirable to iterate over the contents of the nodes in the tree and do a pattern match. Unfortunately there isn't a straightforward way to do this in c# without writing some custom code. I don't like writing a custom function each time I need to do something like this, and the great thing about generics is that allows sufficient abstraction of types and functions to allow generalizing a pattern like this. <br /><br />Let us define a basic abstraction of a tree element <br /> <div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"> <div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> IElement</pre><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> IEnumerable<IElement> Children { get; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> }</pre> </div></div><br />In a nutshell that's all you need. A tree node is a structure where each element has children that can be iterated over, and the hierarchy of all the elements defines the tree structure. This is of course a generalization, as we could put additional constraints such as each element being only available once in the tree, but I'll leave it up to the developer to enforce such constraints. I'm merely trying to iterate over the tree nodes.<br /><p>With that in mind, we can define a function that maps</p><div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> IElement -> IEnumerable<IElement></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> Func<IElement, IEnumerable<IElement>> childrenMappingFunction;</pre> </div></div><p>There are two common ways to do recursion: function recursion where a function points to itself, or stack-based recursion where we use a stack to keep a list of evaluation arguments on a stack and evaluate them as need be. We'll use stack-based iteration because it tends to be more scalable.</p><p>Without further ado let’s get to the meat of the code:</p><div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> IEnumerable<T> Enumerate<T>(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> T rootItem, </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> Func<T, IEnumerable<T>> childrenMappingFunction, </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> <span style="color: rgb(0, 0, 255);">bool</span> returnRoot)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 5:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 6:</span> Stack<T> workStack = <span style="color: rgb(0, 0, 255);">new</span> Stack<T>();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 7:</span> workStack.Push(rootItem);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 8:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 9:</span> <span style="color: rgb(0, 0, 255);">bool</span> isRoot = <span style="color: rgb(0, 0, 255);">true</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 10:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 11:</span> <span style="color: rgb(0, 0, 255);">while</span> (workStack.Count > 0)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 12:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 13:</span> T item = workStack.Pop();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 14:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 15:</span> <span style="color: rgb(0, 0, 255);">if</span> (isRoot)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 16:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 17:</span> <span style="color: rgb(0, 0, 255);">if</span> (returnRoot)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 18:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 19:</span> <span style="color: rgb(0, 0, 255);">yield</span> <span style="color: rgb(0, 0, 255);">return</span> item;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 20:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 21:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 22:</span> isRoot = <span style="color: rgb(0, 0, 255);">false</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 23:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 24:</span> <span style="color: rgb(0, 0, 255);">else</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 25:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 26:</span> <span style="color: rgb(0, 0, 255);">yield</span> <span style="color: rgb(0, 0, 255);">return</span> item;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 27:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 28:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 29:</span> IEnumerable<T> children = childrenMappingFunction(item);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 30:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 31:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (T child <span style="color: rgb(0, 0, 255);">in</span> children)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 32:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 33:</span> workStack.Push(child);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 34:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 35:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 36:</span> }</pre> </div></div><br />Let’s look at what the code does. It first creates a stack to hold the objects that need to be evaluated. It then pushes the root item onto the stack. The loop is quite simple. While the stack has items in it, first pop an item off the stack, yield it using the c# iterator pattern, then call childrenMappingFunction to get the children (IEnumerable<T>) from T item. Then, for each child in children, add the child to the stack, so that it is evaluated on the next iteration of the while loop. That’s pretty much it. Because of the elegance of c# iterators, it’s easy to use this function to map a tree to a flatter IEnumerable<T> without ever having to concern ourselves with the details again.<br /><p>I’ve added some additional overloads and parameters to allow customizing how we get the data back. The only one that might need a bit of explanation is leftToRight. What I discovered when first using this class is that because of the way items are added to the stack, the elements returned from the function are not necessarily in the same order that they were in each nodes IEnumerable. This is not always a problem, but certainly can be in certain use cases so I added a modifier, leftToRight, that ensures that the data is added to the stack in reverse order, so that when it is popped off the stack, it’s in the order that the elements were returned from IEnumerable. It’s not the most efficient way to do this and I recognize that, but I don’t use that option most of the time and in the cases where I did use it performance was not a major concern. If anyone wants to provide a cleaner implementation I welcome feedback. Here is the class in it’s entirety:</p><div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">class</span> DeepEnumerator</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> IEnumerable<T> Enumerate<T>(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> IEnumerable<T> rootItems, </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 5:</span> Func<T, IEnumerable<T>> childrenMappingFunction)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 6:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 7:</span> <span style="color: rgb(0, 0, 255);">return</span> Enumerate(rootItems, childrenMappingFunction, <span style="color: rgb(0, 0, 255);">true</span>, <span style="color: rgb(0, 0, 255);">true</span>);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 8:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 9:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 10:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> IEnumerable<T> Enumerate<T>(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 11:</span> IEnumerable<T> rootItems, </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 12:</span> Func<T, IEnumerable<T>> childrenMappingFunction, </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 13:</span> <span style="color: rgb(0, 0, 255);">bool</span> returnRootItems, </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 14:</span> <span style="color: rgb(0, 0, 255);">bool</span> enumerateDeep)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 15:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 16:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (T rootItem <span style="color: rgb(0, 0, 255);">in</span> rootItems)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 17:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 18:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (T item <span style="color: rgb(0, 0, 255);">in</span> Enumerate(rootItem, childrenMappingFunction, returnRootItems, enumerateDeep, <span style="color: rgb(0, 0, 255);">true</span>))</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 19:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 20:</span> <span style="color: rgb(0, 0, 255);">yield</span> <span style="color: rgb(0, 0, 255);">return</span> item;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 21:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 22:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 23:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 24:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 25:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> IEnumerable<T> Enumerate<T>(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 26:</span> T rootItem, </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 27:</span> Func<T, IEnumerable<T>> childrenMappingFunction)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 28:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 29:</span> <span style="color: rgb(0, 0, 255);">return</span> Enumerate(rootItem, childrenMappingFunction, <span style="color: rgb(0, 0, 255);">true</span>, <span style="color: rgb(0, 0, 255);">true</span>, <span style="color: rgb(0, 0, 255);">true</span>);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 30:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 31:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 32:</span> <span style="color: rgb(0, 0, 255);">public</span> <span style="color: rgb(0, 0, 255);">static</span> IEnumerable<T> Enumerate<T>(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 33:</span> T rootItem, </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 34:</span> Func<T, IEnumerable<T>> childrenMappingFunction, </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 35:</span> <span style="color: rgb(0, 0, 255);">bool</span> returnRoot, </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 36:</span> <span style="color: rgb(0, 0, 255);">bool</span> enumerateDeep, </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 37:</span> <span style="color: rgb(0, 0, 255);">bool</span> leftToRight)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 38:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 39:</span> <span style="color: rgb(0, 0, 255);">if</span> (enumerateDeep)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 40:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 41:</span> Stack<T> workStack = <span style="color: rgb(0, 0, 255);">new</span> Stack<T>();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 42:</span> workStack.Push(rootItem);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 43:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 44:</span> <span style="color: rgb(0, 0, 255);">bool</span> isRoot = <span style="color: rgb(0, 0, 255);">true</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 45:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 46:</span> <span style="color: rgb(0, 0, 255);">while</span> (workStack.Count > 0)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 47:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 48:</span> T item = workStack.Pop();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 49:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 50:</span> <span style="color: rgb(0, 0, 255);">if</span> (isRoot)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 51:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 52:</span> <span style="color: rgb(0, 0, 255);">if</span> (returnRoot)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 53:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 54:</span> <span style="color: rgb(0, 0, 255);">yield</span> <span style="color: rgb(0, 0, 255);">return</span> item;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 55:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 56:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 57:</span> isRoot = <span style="color: rgb(0, 0, 255);">false</span>;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 58:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 59:</span> <span style="color: rgb(0, 0, 255);">else</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 60:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 61:</span> <span style="color: rgb(0, 0, 255);">yield</span> <span style="color: rgb(0, 0, 255);">return</span> item;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 62:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 63:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 64:</span> IEnumerable<T> children = childrenMappingFunction(item);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 65:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 66:</span> <span style="color: rgb(0, 0, 255);">if</span> (leftToRight)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 67:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 68:</span> children = EnumerateListBackwards(children.ToList());</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 69:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 70:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 71:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (T child <span style="color: rgb(0, 0, 255);">in</span> children)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 72:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 73:</span> workStack.Push(child);</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 74:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 75:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 76:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 77:</span> <span style="color: rgb(0, 0, 255);">else</span></pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 78:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 79:</span> <span style="color: rgb(0, 0, 255);">yield</span> <span style="color: rgb(0, 0, 255);">return</span> rootItem;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 80:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (T item <span style="color: rgb(0, 0, 255);">in</span> childrenMappingFunction(rootItem))</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 81:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 82:</span> <span style="color: rgb(0, 0, 255);">yield</span> <span style="color: rgb(0, 0, 255);">return</span> item;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 83:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 84:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 85:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 86:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 87:</span> <span style="color: rgb(0, 0, 255);">private</span> <span style="color: rgb(0, 0, 255);">static</span> IEnumerable<T> EnumerateListBackwards<T>(List<T> list)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 88:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 89:</span> <span style="color: rgb(0, 0, 255);">for</span> (<span style="color: rgb(0, 0, 255);">int</span> index = list.Count - 1; index >= 0; index--)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 90:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 91:</span> <span style="color: rgb(0, 0, 255);">yield</span> <span style="color: rgb(0, 0, 255);">return</span> list[index];</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 92:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 93:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 94:</span> }</pre> </div></div><p>Let’s look at a use case:<br /><br />Given a .Net Winforms TreeView, find all nodes in the entire tree that start with E.</p><p>Because Node.Nodes does not implement IEnumerable<Node> we need a helper function, so we’ll use that with the deep enumerator.</p><div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> <span style="color: rgb(0, 0, 255);">private</span> <span style="color: rgb(0, 0, 255);">static</span> Enumerable<TreeNode> IterateNodes(TreeNodeCollection treeNodes)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (TreeNode childNode <span style="color: rgb(0, 0, 255);">in</span> treeNodes)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 5:</span> <span style="color: rgb(0, 0, 255);">yield</span> <span style="color: rgb(0, 0, 255);">return</span> childNode;</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 6:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 7:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 8:</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 9:</span> TreeView treeView = <span style="color: rgb(0, 0, 255);">new</span> TreeView();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 10:</span> <span style="color: rgb(0, 0, 255);">foreach</span> (TreeNode treeNode <span style="color: rgb(0, 0, 255);">in</span> </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 11:</span> DeepEnumerator.Enumerate(</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 12:</span> IterateNodes(treeView.Nodes), </pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 13:</span> node => IterateNodes(node.Nodes)))</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 14:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 15:</span> <span style="color: rgb(0, 0, 255);">if</span> (treeNode.Text.StartsWith(<span style="color: rgb(0, 96, 128);">"E"</span>))</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 16:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 17:</span> Do Something.</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 18:</span> }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 19:</span> }</pre> </div></div><p>For a second example let us define a slightly cleaner interface:</p><div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> <span style="color: rgb(0, 0, 255);">private</span> <span style="color: rgb(0, 0, 255);">interface</span> ITextNode</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> {</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> <span style="color: rgb(0, 0, 255);">string</span> Text { get; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> IEnumerable<ITextNode> Children { get; }</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 5:</span> }</pre> </div></div><p>What if we wanted to find all nodes in List<ITextNode> nodes where one or more of the children (root included) start with the letter E.</p><p>Using LINQ this is pretty straightforward:</p><div style="border: 1px solid gray; margin: 20px 0px 10px; padding: 4px; overflow: auto; line-height: 12pt; background-color: rgb(244, 244, 244); width: 97.5%; max-height: 200px; cursor: text;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;"><div style="border-style: none; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 1:</span> List<ITextNode> textNodes = <span style="color: rgb(0, 0, 255);">new</span> List<ITextNode>();</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 2:</span> var nodesWithOneOrMoreChildrenStartingWithLetterE =</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 3:</span> from textNode <span style="color: rgb(0, 0, 255);">in</span> textNodes</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 4:</span> let children = DeepEnumerator.Enumerate(textNode, node => node.Children)</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 5:</span> let countWithLetterE = children.Where(node => node.Text.StartsWith(<span style="color: rgb(0, 96, 128);">"E"</span>)).Count()</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: rgb(244, 244, 244); width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 6:</span> <span style="color: rgb(0, 0, 255);">where</span> countWithLetterE > 0</pre> <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; line-height: 12pt; background-color: white; width: 100%;font-family:consolas,'Courier New',courier,monospace;font-size:8pt;color:black;"><span style="color: rgb(96, 96, 96);"> 7:</span> select textNode;</pre> </div></div><p>These are just a few examples. I hope you find this class useful. Deep tree enumeration is something I find myself doing fairly often, and this class has eliminated a lot of redundant code for me.</p>Brooke Philpotthttp://www.blogger.com/profile/08943147081689036679noreply@blogger.com1tag:blogger.com,1999:blog-7109482435925565923.post-28572093096469346382008-10-08T18:03:00.000-04:002008-10-08T18:29:01.398-04:00About the TitleThe never-ending staircase is one of the elements of an illustration by M. C. Escher called "Ascending and Descending". The reason I chose such a title for my blog is because to me programming has always seemed like an infinite series of steps. There seems to be no limit to what we can learn or how far we can push ourselves given enough time and effort.<br /><br />The purpose of this blog is to to share with the community some of those steps of mine. In addition, occasionally (at least in my experience) there seem to be moments of extreme clarity, where paradigm shifts occur and many steps are taken in a short amount of time. At times in retrospect I wish I had documented such moments before and I hope this blog can become a channel for some of those ideas. While I expect the majority of my posts will cover code and language, some may cover architecture as well.<br /><br />I hope everyone finds my posts to be useful and I strongly encourage feedback from anyone who happens to stumble upon this blog.Brooke Philpotthttp://www.blogger.com/profile/08943147081689036679noreply@blogger.com2