<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-4063545436138319205</id><updated>2026-04-19T13:29:09.720-07:00</updated><category term=".NET"/><category term="Unit Testing"/><category term="MVC"/><category term="xUnit"/><category term="ORM"/><category term="Dependency Injection"/><category term="ASP.NET"/><category term="TDD"/><category term="JavaScript"/><category term="Unity"/><category term="NuGet"/><category term="Performance"/><category term="Presentations"/><category term="Configuration"/><category term="jQuery"/><category term=".NET Core"/><category term="Async"/><category term="Best Practices"/><category term="DI"/><category term="Data Driven Unit Test"/><category term="IOC"/><category term="JSON"/><category term="Inversion of Control"/><category term="RavenDB"/><category term="Selenium"/><category term="WebDriver"/><category term="C#"/><category term="Code Generation"/><category term="HTTP"/><category term="TypeScript"/><category term="Web API 2"/><category term="AppConfig"/><category term="Bundle"/><category term="Caching"/><category term="ConfigurationSection"/><category term="HttpClient"/><category term="Minification"/><category term="WebAPI"/><category term="WebSockets"/><category term="await"/><category term="Cache"/><category term="Common Logging"/><category term="Fleck"/><category term="Json.Net"/><category term="NLog"/><category term="PhantomJS"/><category term="Reflection"/><category term="Resharper"/><category term="Semaphore"/><category term="TPL"/><category term="Theory"/><category term="Thread Safety"/><category term="Visual Studio"/><category term=".NET Standard"/><category term="Basic Authentication"/><category term="CSharp"/><category term="Chrome"/><category term="Command Line"/><category term="Compression"/><category term="Concurrency"/><category term="Delegate"/><category term="Digest Authentication"/><category term="Entity Framework"/><category term="ExtJS"/><category term="HttpWebRequest"/><category term="InlineData"/><category term="Invoke"/><category term="Lazy"/><category term="LinqToSql"/><category term="Logging"/><category term="MVC4"/><category term="Newtonsoft"/><category term="QUnit"/><category term="Regex"/><category term="SQLite"/><category term="SemaphoreSlim"/><category term="Serializable"/><category term="Serialization"/><category term="String.Concat"/><category term="Tact"/><category term="Tact.NET"/><category term="Task Parallel Library"/><category term="Throttle"/><category term="Web Optimization"/><category term="WebSocket Server"/><category term="WebSocket4Net"/><category term="Analyzer"/><category term="BlockingCollection"/><category term="Build"/><category term="BundleTransformer"/><category term="CSS"/><category term="Child Process"/><category term="Combres"/><category term="ConcurrentQueue"/><category term="Dataflow"/><category term="Default Parameter"/><category term="Delegates"/><category term="Dynamic"/><category term="Dynamic Object"/><category term="Dynamics"/><category term="EDD"/><category term="Exception Driven Development"/><category term="Exceptionless"/><category term="ExpandoObject"/><category term="Generic"/><category term="Generic Constraints"/><category term="IEnumerable"/><category term="ITestOutputHelper"/><category term="Interface"/><category term="InteropServices"/><category term="JavaScriptErrorReporter"/><category term="JsonConverter"/><category term="Kernal32.dll"/><category term="LESS"/><category term="LINQ To SQL"/><category term="Lucene.Net"/><category term="MP3"/><category term="MvcBundleConfig"/><category term="NHibernate"/><category term="NUnit"/><category term="NetCoreApp"/><category term="Optimization"/><category term="Optional Parameter"/><category term="PagedList"/><category term="Process"/><category term="Properties"/><category term="Regular Expression"/><category term="String.Format"/><category term="StringBuilder"/><category term="TFS"/><category term="Task"/><category term="Threading"/><category term="Throttling"/><category term="WebSocket Client"/><category term="Windows 8"/><category term="Windows Service"/><category term="dotnet"/><category term="using"/><category term="xUnit 2.0"/><category term="Abstract"/><category term="ActionBlock"/><category term="Activator"/><category term="AggressiveInlining"/><category term="Ajax"/><category term="AllowAutoRedirect"/><category term="Ambiguous Invocation"/><category term="Android"/><category term="Angular"/><category term="AngularJS"/><category term="Asynchronous"/><category term="Attribute"/><category term="Autofac"/><category term="B"/><category term="Batch"/><category term="Batch Queries"/><category term="Behaviors"/><category term="Big O Notation"/><category term="Binary Tree"/><category term="BlockingQueue"/><category term="Bootstrap"/><category term="Boxing"/><category term="Browser Link"/><category term="BufferBlock"/><category term="Build Server"/><category term="CSProj"/><category term="Caller Information"/><category term="CallerMemberNameAttribute"/><category term="Callsite"/><category term="CancellationTokenSource"/><category term="Cassandra"/><category term="Chromecast"/><category term="Class"/><category term="Collections"/><category term="Combine Hash Codes"/><category term="Compile"/><category term="Compile on Save"/><category term="Compiled"/><category term="ConcurrentDictionary"/><category term="Config Transform"/><category term="Conflict Resolver"/><category term="Connection Management"/><category term="ConnectionLimit"/><category term="Console"/><category term="Constructorinfo"/><category term="Container"/><category term="Continuous Deployment"/><category term="Continuous Integration"/><category term="CookieContainer"/><category term="Couchbase"/><category term="CredentialCache"/><category term="CustomModelBinderAttribute"/><category term="DOS"/><category term="Data Structures"/><category term="Debug"/><category term="Debugging"/><category term="Definition"/><category term="Deployment"/><category term="Dipose"/><category term="DosBox Turbo"/><category term="DotNetCliToolReference"/><category term="DynamicInvoke"/><category term="EAP"/><category term="Emulators"/><category term="Enum"/><category term="Error Handling"/><category term="Error Reporting"/><category term="Event Handling"/><category term="Events"/><category term="Exception Filter"/><category term="Explicit Cast"/><category term="Expression"/><category term="Extension Methods"/><category term="File"/><category term="FileResult"/><category term="Find"/><category term="FireAndForget"/><category term="Foobar"/><category term="Future Queries"/><category term="GOG"/><category term="Generic Method"/><category term="GetHashCodeAggregate"/><category term="GetOrAdd"/><category term="GhostDriver"/><category term="Group"/><category term="HTML5"/><category term="HandleErrorAttribute"/><category term="Hash"/><category term="Hash Code"/><category term="Headless Browser"/><category term="Http Connection"/><category term="HttpClientHandler"/><category term="HttpContent"/><category term="IDisposable"/><category term="IIS"/><category term="IServiceCollection"/><category term="IdentityReference"/><category term="Implicit Cast"/><category term="IntelliSense"/><category term="Internet Explorer"/><category term="InternetExplorerDriver"/><category term="InvalidOperationException"/><category term="JObject"/><category term="JSONP"/><category term="JToken"/><category term="JsonContent"/><category term="Kafka"/><category term="Key"/><category term="KeyedSemaphoreSlim"/><category term="Last In Win"/><category term="Lifetime Manager"/><category term="Local Traffic"/><category term="MSTest"/><category term="Master of Orion"/><category term="MemoryStream"/><category term="Microsoft"/><category term="Microsoft.Build"/><category term="Mock"/><category term="ModelState"/><category term="MongoDB"/><category term="Moq"/><category term="Music"/><category term="NSubstitute"/><category term="Named Registration"/><category term="Naming Conventions"/><category term="NuGet3"/><category term="OAuth"/><category term="OS"/><category term="Object Orientation"/><category term="ObjectPool"/><category term="Octopus"/><category term="Overloaded Method"/><category term="Owin"/><category term="Pack"/><category term="Package Restore"/><category term="Packages"/><category term="Packet Capture"/><category term="Partition"/><category term="Playlist"/><category term="Podcast"/><category term="Pooling"/><category term="PossibleMultipleEnumeration"/><category term="Power Tools"/><category term="PreAuthenticate"/><category term="Pretty print"/><category term="ProjectCollection"/><category term="PropertyInfo"/><category term="Python"/><category term="RabbitMQ"/><category term="Range Set"/><category term="RawCap"/><category term="ReadAllText"/><category term="Red Black Tree"/><category term="Redis"/><category term="Reflector"/><category term="RegexOptions"/><category term="RegisterAll"/><category term="Replace"/><category term="Replace Word"/><category term="Replication"/><category term="Routing"/><category term="RuntimeBinderException"/><category term="SASS"/><category term="SNES"/><category term="SPC"/><category term="Set"/><category term="SetValue"/><category term="Shelveset"/><category term="SignalR"/><category term="SortedDictionary"/><category term="Source"/><category term="Stack Frame"/><category term="StackTrace.js"/><category term="Status Code"/><category term="Stream"/><category term="String Interpolation"/><category term="String.Split"/><category term="Struct"/><category term="StyleCop"/><category term="Symbols"/><category term="TAP"/><category term="Team Foundation Server"/><category term="Technology Radar"/><category term="Test Case Order"/><category term="Test Collection Order"/><category term="Test Output"/><category term="TestCase"/><category term="ThoughtWorks"/><category term="Timeout"/><category term="Touch"/><category term="Touch Events"/><category term="Transaction"/><category term="TransformBlock"/><category term="Translate"/><category term="Tuple"/><category term="Unboxing"/><category term="Unshelve"/><category term="User Impersonation"/><category term="VS2015"/><category term="VSCode"/><category term="Visual Studio 2013"/><category term="Visual Studio 2015"/><category term="WebClient"/><category term="WhenAny"/><category term="Windows Authentication"/><category term="WireShark"/><category term="Word Boundaries"/><category term="XDT"/><category term="XML Document Transformations"/><category term="XNA"/><category term="ajaxPrefilter"/><category term="cli"/><category term="console app"/><category term="console runner"/><category term="constructor"/><category term="dotLess"/><category term="dotPeek"/><category term="dotnet-test-xunit"/><category term="jQuery Mobile"/><category term="log4net"/><category term="new"/><category term="testRunner"/><category term="tool"/><category term="vs2017"/><category term="window.onerror"/><title type='text'>Tom DuPont .NET</title><subtitle type='html'>I&#39;m a tool, so you don&#39;t have to be.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.tomdupont.net/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default?start-index=26&amp;max-results=25&amp;redirect=false'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>224</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-7393679217032270671</id><published>2017-04-27T08:01:00.000-07:00</published><updated>2017-04-27T08:38:30.816-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET Core"/><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET"/><category scheme="http://www.blogger.com/atom/ns#" term="Container"/><category scheme="http://www.blogger.com/atom/ns#" term="DI"/><category scheme="http://www.blogger.com/atom/ns#" term="IOC"/><category scheme="http://www.blogger.com/atom/ns#" term="IServiceCollection"/><category scheme="http://www.blogger.com/atom/ns#" term="Unity"/><title type='text'>Creating an IOC Container for ASP.NET Core</title><content type='html'>&lt;img style=&quot;float:right;margin-left:20px;&quot; src=&quot;http://sites.google.com/site/tdupont750/microsoft_patterns_practices.gif&quot;&gt;

&lt;p&gt;I recently added support for ASP.NET Core to my &lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/framework/src/Tact.AspNetCore/Practices/Implementation/AspNetCoreContainer.cs&quot; target=&quot;_blank&quot;&gt;Tact.NET IOC Container&lt;/a&gt;, and I thought that I would share some of the interesting requirements I discovered while doing so. I had originally expected the default ASP.NET Core container would follow the same rules as the official Microsoft Unity container, but that turned out not to be the case!&lt;/p&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;1) Register is first in win.&lt;/h3&gt;

&lt;p&gt;The Unity container was last in win, and it would completely disregard the original registration. With ASP.NET Core you need to preserve the original registration and then treat all subsequent registrations as addition registrations that will only be resolved when ResolveAll is invoked, similar to keyed registrations in Unity. Which brings us to our next difference...&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; RegisterIsFirstInWinTests&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    [Fact]&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Unity()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; log = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; EmptyLog();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; container = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; TactContainer(log))&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            container.RegisterSingleton&amp;lt;IExample, ExampleA&amp;gt;();&lt;/pre&gt;
&lt;pre&gt;            container.RegisterSingleton&amp;lt;IExample, ExampleB&amp;gt;();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; example = container.Resolve&amp;lt;IExample&amp;gt;();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            Assert.IsType&amp;lt;ExampleB&amp;gt;(example);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    [Fact]&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; AspNetCore()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; log = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; EmptyLog();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; container = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; AspNetCoreContainer(log))&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            container.RegisterSingleton&amp;lt;IExample, ExampleA&amp;gt;();&lt;/pre&gt;
&lt;pre&gt;            container.RegisterSingleton&amp;lt;IExample, ExampleB&amp;gt;();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; example = container.Resolve&amp;lt;IExample&amp;gt;();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            Assert.IsType&amp;lt;ExampleA&amp;gt;(example);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IExample&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Name { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ExampleA : IExample&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Name =&amp;gt; nameof(ExampleA);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ExampleB : IExample&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Name =&amp;gt; nameof(ExampleB);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;2) ResolveAll includes single registrations.&lt;/h3&gt;

&lt;p&gt;Unity has the concept of keyed registrations, where you can register the same type multiple times with distinct keys (strings) and then resolve them individually by key or as an IEnumerable with ResolveAll. In ASP.NET Core there is no concept of keyed registration, and ResolveAll will return all registrations made for a given type. This means that registering a single type will cause ResolveAll to return an IEnumerable with one value.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ResolveAllIncludesSingleRegistrations&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    [Fact]&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Unity()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; log = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; EmptyLog();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; container = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; TactContainer(log))&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            container.RegisterSingleton&amp;lt;IExample, ExampleA&amp;gt;();&lt;/pre&gt;
&lt;pre&gt;            container.RegisterSingleton&amp;lt;IExample, ExampleB&amp;gt;();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; examples = container.ResolveAll&amp;lt;IExample&amp;gt;();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            Assert.Equal(0, examples.Count());&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    [Fact]&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; AspNetCore()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; log = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; EmptyLog();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; container = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; AspNetCoreContainer(log))&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            container.RegisterSingleton&amp;lt;IExample, ExampleA&amp;gt;();&lt;/pre&gt;
&lt;pre&gt;            container.RegisterSingleton&amp;lt;IExample, ExampleB&amp;gt;();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; examples = container.ResolveAll&amp;lt;IExample&amp;gt;();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            Assert.Equal(2, examples.Count());&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IExample&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Name { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ExampleA : IExample&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Name =&amp;gt; nameof(ExampleA);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ExampleB : IExample&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; Name =&amp;gt; nameof(ExampleB);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;3) Generic resolution is required.&lt;/h3&gt;

&lt;p&gt;This was a neat feature that I had not used before! You can register generic types without any generic parameters, and then the container will fill in the generic parameters based on the resolve request. So, for example,
 I could register IRepository&amp;lt;&amp;gt; to type DataRepository&amp;lt;&amp;gt;, and then when I call container.Resolve&amp;lt;IRepository&amp;lt;User&amp;gt;&amp;gt;, the IOC container will automatically try to construct a DataRepository&amp;lt;User&amp;gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; TactContainerTests&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    [Fact]&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; GenericResolution()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; log = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; EmptyLog();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; container = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; TactContainer(log))&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            container.RegisterSingleton(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(IRepository&amp;lt;&amp;gt;), &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(Repository&amp;lt;&amp;gt;));&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; userRepository = container.Resolve&amp;lt;IRepository&amp;lt;User&amp;gt;&amp;gt;();&lt;/pre&gt;
&lt;pre&gt;            Assert.IsType&amp;lt;Repository&amp;lt;User&amp;gt;&amp;gt;(userRepository);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;interface&lt;/span&gt; IRepository&amp;lt;T&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; ClassName { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; GenericName { &lt;span class=&quot;kwrd&quot;&gt;get&lt;/span&gt;; }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Repository&amp;lt;T&amp;gt; : IRepository&amp;lt;T&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; ClassName =&amp;gt; nameof(Repository&amp;lt;T&amp;gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; GenericName =&amp;gt; &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(T).Name;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; User&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;4) You have to convert IServiceCollection to your container.&lt;/h3&gt;

&lt;p&gt;I like how the new .NET separates their service registration from the container itself. In your ASP.NET Core wire up you will work with an IServiceCollection, which will then be converted into a container after you are done filling in your registrations. This means that if you want to create your own container, you will need to map the service collection into your container.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/framework/demo/Demo.Tact.AspNetCore/Startup.cs#L33&quot; target=&quot;_blank&quot;&gt;ASP.NET Core Registration Example&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/framework/src/Tact.AspNetCore/Practices/Implementation/AspNetCoreContainer.cs#L80&quot; target=&quot;_blank&quot;&gt;Registration Conversion Example&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/7393679217032270671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2017/04/creating-ioc-container-for-aspnet-core.html#comment-form' title='32 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/7393679217032270671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/7393679217032270671'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2017/04/creating-ioc-container-for-aspnet-core.html' title='Creating an IOC Container for ASP.NET Core'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>32</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-4019652847057602035</id><published>2017-04-16T09:31:00.000-07:00</published><updated>2017-04-16T09:35:01.436-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="cli"/><category scheme="http://www.blogger.com/atom/ns#" term="Command Line"/><category scheme="http://www.blogger.com/atom/ns#" term="console app"/><category scheme="http://www.blogger.com/atom/ns#" term="dotnet"/><category scheme="http://www.blogger.com/atom/ns#" term="DotNetCliToolReference"/><category scheme="http://www.blogger.com/atom/ns#" term="NetCoreApp"/><category scheme="http://www.blogger.com/atom/ns#" term="NuGet"/><category scheme="http://www.blogger.com/atom/ns#" term="tool"/><category scheme="http://www.blogger.com/atom/ns#" term="vs2017"/><title type='text'>How to make a dotnet CLI Tool</title><content type='html'>&lt;p&gt;Good news, everyone! It is remarkably easy to make a new &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/articles/core/tools/&quot; target=&quot;_blank&quot;&gt;dotnet CLI (Command Line Interface) tool&lt;/a&gt;! I recently created a CLI tool for one of my new projects, &lt;a href=&quot;http://www.tomdupont.net/2016/10/introducing-tactnet.html&quot; target=&quot;_blank&quot;&gt;Tact.NET&lt;/a&gt; RPC, and in this post I will be referencing that project as my example.&lt;/p&gt;

&lt;p&gt;&lt;h2&gt;The Basics&lt;/h2&gt;&lt;/p&gt;

&lt;p&gt;&lt;h3&gt;Step 1) Create your CLI Console App&lt;/h3&gt;&lt;/p&gt;

&lt;p&gt;All you have to do is...&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a normal .NET Core Console App. &lt;ul&gt;&lt;li&gt;&lt;i&gt;NOTE: Currently, the dotnet CLI only supports &lt;b&gt;netcoreapp1.0&lt;/b&gt;&lt;/i&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Rename the assembly to be prefixed with &quot;dotnet-&quot;&lt;/li&gt;
&lt;li&gt;dotnet pack the project and put the package in your local NuGet package source&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;...that is it! It is literally that easy to create your CLI tool!&lt;/p&gt;

&lt;p style=&quot;text-align:center&quot;&gt;&lt;img src=&quot;https://sites.google.com/site/tdupont750/dotnet_cli_new_project.PNG&quot; style=&quot;max-width:800px; min-width:400px;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Recommendation: use &lt;a href=&quot;https://www.nuget.org/packages/Microsoft.Extensions.Configuration.CommandLine/&quot; target=&quot;_blank&quot;&gt;Microsoft.Extensions.Configuration&lt;/a&gt; to parse your command line arguments in a standard way.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;Project&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;Sdk&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;Microsoft.NET.Sdk&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;OutputType&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;Exe&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;OutputType&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;TargetFramework&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;netcoreapp1.0&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;TargetFramework&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;AssemblyName&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;dotnet-tactrpcgen&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;AssemblyName&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PackageId&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;Tact.Rpc.Generator&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PackageId&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;1.0.3&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PackageReference&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;Microsoft.Extensions.Configuration.CommandLine&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;1.1.1&quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;h3&gt;Step 2) Consume your CLI Tool NuGet Package&lt;/h3&gt;&lt;/p&gt;

&lt;p&gt;Edit your csproj file and add a DotNetCliToolReference element that references your package.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;Project&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;Sdk&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;Microsoft.NET.Sdk&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;TargetFramework&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;netstandard1.6&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;TargetFramework&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;DotNetCliToolReference&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;Tact.Rpc.Generator&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;1.0.3&quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Now you are able to invoke your console app via the dotnet command line whenever it is executed in the same path as the csproj.&lt;/p&gt;

&lt;p style=&quot;text-align:center&quot;&gt;&lt;img src=&quot;https://sites.google.com/site/tdupont750/dotnet_cli_tool.PNG&quot; style=&quot;max-width:800px; min-width:400px;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That&#39;s it; it really is that easy!&lt;/p&gt;

&lt;p&gt;&lt;h2&gt;Development Tips&lt;/h2&gt;&lt;/p&gt;

&lt;p&gt;Here is a simple way to automate the creation and consumption of your CLI tool NuGet package during development.&lt;/p&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;img src=&quot;https://sites.google.com/site/tdupont750/nuget_config.PNG&quot; style=&quot;float:right; margin-left:20px;&quot; /&gt;

&lt;p&gt;&lt;h3&gt;Create a local package directory&lt;/h3&gt;&lt;/p&gt;

&lt;p&gt;I recommend that you create a packages folder at the root of your solution along with a NuGet.config file; this will allow you to automatically build and consume NuGet packages from this location.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;packageSources&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;LocalPackages&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;packages&quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;packageSources&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;h3&gt;Pack on post build&lt;/h3&gt;&lt;/p&gt;

&lt;p&gt;Go back and update your CLI tool&#39;s csproj to include a post build step that packs your project and places the output in your package folder. (There is a csproj GeneratePackageOnBuild setting, however at this time I do not believe that you can customize the output directory, so instead I recommend using a post build step.)&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;Project&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;Sdk&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;Microsoft.NET.Sdk&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;OutputType&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;Exe&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;OutputType&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;TargetFramework&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;netcoreapp1.0&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;TargetFramework&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;AssemblyName&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;dotnet-tactrpcgen&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;AssemblyName&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PackageId&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;Tact.Rpc.Generator&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PackageId&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;RunPostBuildEvent&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;OnBuildSuccess&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;RunPostBuildEvent&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PostBuildEvent&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;      dotnet pack $(SolutionDir)rpc\src\Tact.Rpc.Generator -o $(SolutionDir)packages --no-build&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PostBuildEvent&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;1.0.3&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PackageReference&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;Microsoft.Extensions.Configuration.CommandLine&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;1.1.1&quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;h3&gt;Execute on pre build&lt;/h3&gt;&lt;/p&gt;

&lt;p&gt;Obviously this is a completely optional step that should only be used when necessary; in the case of Tact.NET RPC, the active code generation is powered by the CLI tool, and thus it needs to run every build.&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;Project&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;Sdk&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;Microsoft.NET.Sdk&quot;&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;TargetFramework&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;netstandard1.6&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;TargetFramework&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PreBuildEvent&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;      cd $(SolutionDir)rpc\demo\Demo.Rpc&lt;/pre&gt;
&lt;pre&gt;      dotnet tactrpcgen&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PreBuildEvent&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;DotNetCliToolReference&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;Tact.Rpc.Generator&quot;&lt;/span&gt; &lt;span class=&quot;attr&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;=&quot;1.0.3&quot;&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  &lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;html&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;&lt;h3&gt;Increment version to update&lt;/h3&gt;&lt;/p&gt;

&lt;p&gt;NOTE: Despite updating the your local package directory each build, the package will actually be cached in your global NuGet cache, and thus updates will not be picked up unless you increment the version number.&lt;/p&gt;

&lt;p&gt;Enjoy,&lt;br&gt;
Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/4019652847057602035/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2017/04/how-to-make-dotnet-cli-tool.html#comment-form' title='17 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/4019652847057602035'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/4019652847057602035'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2017/04/how-to-make-dotnet-cli-tool.html' title='How to make a dotnet CLI Tool'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-2562626917681623572</id><published>2017-03-30T08:00:00.000-07:00</published><updated>2017-04-02T17:28:03.169-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="Performance"/><category scheme="http://www.blogger.com/atom/ns#" term="String Interpolation"/><category scheme="http://www.blogger.com/atom/ns#" term="String.Concat"/><category scheme="http://www.blogger.com/atom/ns#" term="String.Format"/><category scheme="http://www.blogger.com/atom/ns#" term="StringBuilder"/><title type='text'>C# String Interpolation Performance</title><content type='html'>&lt;p&gt;Time for a follow up to my &lt;a href=&quot;http://www.tomdupont.net/2014/03/string-concat-vs-string-format.html&quot; target=&quot;_blank&quot;&gt;String.Concat vs String.Format Performance&lt;/a&gt; post from back in 2014!&lt;/p&gt;

&lt;p&gt;I recently found out that string interpolation is not nearly as efficient as I would have thought. I also suspected that it was just doing a string concatenation, but it is actually doing a string format. This leads to a pretty significant performance degradation; the following test runs one million iterations of each.&lt;/p&gt;

&lt;table border=&quot;1&quot; style=&quot;margin: 0 auto; text-align:center&quot;&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;th width=&quot;80px&quot;&gt;Number&lt;br&gt;of Args&lt;/th&gt;
&lt;th width=&quot;100px&quot;&gt;Interpolation&lt;br&gt;Milliseconds&lt;/th&gt;
&lt;th width=&quot;100px&quot;&gt;String.Format&lt;br&gt;Milliseconds&lt;/th&gt;
&lt;th width=&quot;100px&quot;&gt;String.Concat&lt;br&gt;Milliseconds&lt;/th&gt;
&lt;th width=&quot;100px&quot;&gt;String Add&lt;br&gt;Milliseconds&lt;/th&gt;
&lt;th width=&quot;100px&quot;&gt;StringBuilder&lt;br&gt;Milliseconds&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;262&lt;/td&gt;
&lt;td&gt;260&lt;/td&gt;
&lt;td&gt;19&lt;/td&gt;
&lt;td&gt;18&lt;/td&gt;
&lt;td&gt;34&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;367&lt;/td&gt;
&lt;td&gt;367&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;35&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;500&lt;/td&gt;
&lt;td&gt;513&lt;/td&gt;
&lt;td&gt;31&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;41&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;646&lt;/td&gt;
&lt;td&gt;635&lt;/td&gt;
&lt;td&gt;67&lt;/td&gt;
&lt;td&gt;66&lt;/td&gt;
&lt;td&gt;44&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;740&lt;/td&gt;
&lt;td&gt;723&lt;/td&gt;
&lt;td&gt;79&lt;/td&gt;
&lt;td&gt;76&lt;/td&gt;
&lt;td&gt;49&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;802&lt;/td&gt;
&lt;td&gt;819&lt;/td&gt;
&lt;td&gt;86&lt;/td&gt;
&lt;td&gt;85&lt;/td&gt;
&lt;td&gt;52&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;938&lt;/td&gt;
&lt;td&gt;936&lt;/td&gt;
&lt;td&gt;97&lt;/td&gt;
&lt;td&gt;98&lt;/td&gt;
&lt;td&gt;58&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;

&lt;p&gt;So, what&#39;s the lesson? Don&#39;t use string interpolation in high performance areas (&lt;a href=&quot;https://github.com/tdupont750/tact.net/blame/master/src/Tact/Diagnostics/Log.generated.tt#L86&quot; target=&quot;_blank&quot;&gt;such as your logger&lt;/a&gt;)!&lt;/p&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/2562626917681623572/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2017/03/c-string-interpolation-performance.html#comment-form' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/2562626917681623572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/2562626917681623572'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2017/03/c-string-interpolation-performance.html' title='C# String Interpolation Performance'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-4553983692855793814</id><published>2017-02-28T08:00:00.000-08:00</published><updated>2017-03-01T19:43:19.367-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET Core"/><category scheme="http://www.blogger.com/atom/ns#" term="Fleck"/><category scheme="http://www.blogger.com/atom/ns#" term="WebSocket4Net"/><category scheme="http://www.blogger.com/atom/ns#" term="WebSockets"/><title type='text'>WebSocket Support for .NET Core</title><content type='html'>&lt;img src=&quot;https://sites.google.com/site/tdupont750/websockets.png&quot; style=&quot;float:right; margin-left:20px; margin-bottom:20px; width:250px;&quot; /&gt;

&lt;p&gt;Full WebSocket support is coming with .NET Standard 2.0, which has now been &lt;a href=&quot;https://github.com/dotnet/core/commit/388215e8715a4ccfac9b22ccf7094a7138a6759b&quot; target=&quot;_blank&quot;&gt;delayed until Q3&lt;/a&gt;. In the meantime, there are still a few options to work with...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Third Party
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/kerryjiang/WebSocket4Net&quot; target=&quot;_blank&quot;&gt;Client - WebSocket4Net - Beta&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/statianzo/Fleck/pull/175&quot; target=&quot;_blank&quot;&gt;Server - Fleck - Pending PR&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Microsoft
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nuget.org/packages/System.Net.WebSockets.Client/&quot; target=&quot;_blank&quot;&gt;Client - System.Net.WebSockets.Client - v4.3.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.nuget.org/packages/Microsoft.AspNetCore.WebSockets.Server/&quot; target=&quot;_blank&quot;&gt;Server - Microsoft.AspNetCore.WebSockets.Server - v0.1.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to use Microsoft.AspNetCore.WebSockets.Server, I have added a middle ware wrapper that feel a lot more like Fleck:&lt;p&gt;

&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/tree/master/src/Tact.AspNetCore.WebSockets.Server&quot; target=&quot;_blank&quot;&gt;Tact.AspNetCore.WebSockets.Server&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot; style=&quot;margin-top:20px&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Configure(IApplicationBuilder app)&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    app.UseWebSockets();&lt;/pre&gt;
&lt;pre&gt;    app.UseWebSocketHandler(&lt;span class=&quot;str&quot;&gt;&quot;test&quot;&lt;/span&gt;, connection =&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// Register your listeners here&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        connection.OnMessage = m =&amp;gt;&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (m == &lt;span class=&quot;str&quot;&gt;&quot;hi&quot;&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;                connection.SendAsync(&lt;span class=&quot;str&quot;&gt;&quot;bye&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        };&lt;/pre&gt;
&lt;pre&gt;    });&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/4553983692855793814/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2017/02/websocket-support-for-net-core.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/4553983692855793814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/4553983692855793814'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2017/02/websocket-support-for-net-core.html' title='WebSocket Support for .NET Core'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-9054849900091147890</id><published>2017-02-26T08:11:00.001-08:00</published><updated>2017-02-26T08:11:35.255-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term=".NET Core"/><category scheme="http://www.blogger.com/atom/ns#" term="dotnet"/><category scheme="http://www.blogger.com/atom/ns#" term="dotnet-test-xunit"/><category scheme="http://www.blogger.com/atom/ns#" term="NetCoreApp"/><category scheme="http://www.blogger.com/atom/ns#" term="Resharper"/><category scheme="http://www.blogger.com/atom/ns#" term="testRunner"/><category scheme="http://www.blogger.com/atom/ns#" term="Unit Testing"/><category scheme="http://www.blogger.com/atom/ns#" term="Visual Studio 2015"/><category scheme="http://www.blogger.com/atom/ns#" term="VS2015"/><category scheme="http://www.blogger.com/atom/ns#" term="xUnit"/><title type='text'>Run .NET Core xUnit tests from ReSharper in VS2015</title><content type='html'>&lt;p&gt;Visual Studio 2017 is literally only a few days away from release; so it might be a little late, but I finally figured out how to run .NET Core xUnit tests from ReSharper in VS2015! Good News: If you can&#39;t upgrade to VS2017 right away, then at least you can still run your unit tests!&lt;/p&gt;

&lt;img style=&quot;float:right; max-width:450px;&quot; src=&quot;https://sites.google.com/site/tdupont750/xUnit_DotNet_ReSharper.png&quot;/&gt;

&lt;p&gt;&lt;b&gt;Just make sure that the following is included in your project.json file (with the appropriate runtime):&lt;/b&gt;&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  &lt;span class=&quot;str&quot;&gt;&quot;testRunner&quot;&lt;/span&gt;: &quot;xunit&quot;,&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  &lt;span class=&quot;str&quot;&gt;&quot;dependencies&quot;&lt;/span&gt;: {&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;str&quot;&gt;&quot;dotnet-test-xunit&quot;&lt;/span&gt;: &quot;2.2.0-preview2-build1029&quot;,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;str&quot;&gt;&quot;xunit&quot;&lt;/span&gt;: &quot;2.2.0&quot;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  },&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  &lt;span class=&quot;str&quot;&gt;&quot;frameworks&quot;&lt;/span&gt;: {&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;str&quot;&gt;&quot;netcoreapp1.0&quot;&lt;/span&gt;: {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;      &lt;span class=&quot;str&quot;&gt;&quot;imports&quot;&lt;/span&gt;: &quot;dnxcore50&quot;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  },&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  &lt;span class=&quot;str&quot;&gt;&quot;runtimes&quot;&lt;/span&gt;: {&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;str&quot;&gt;&quot;win10-x64&quot;&lt;/span&gt;: {}&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/9054849900091147890/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2017/02/run-net-core-xunit-tests-from-resharper.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/9054849900091147890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/9054849900091147890'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2017/02/run-net-core-xunit-tests-from-resharper.html' title='Run .NET Core xUnit tests from ReSharper in VS2015'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-731677427134552933</id><published>2017-01-31T08:48:00.000-08:00</published><updated>2017-02-16T08:27:16.688-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term=".NET Core"/><category scheme="http://www.blogger.com/atom/ns#" term=".NET Standard"/><category scheme="http://www.blogger.com/atom/ns#" term="Autofac"/><category scheme="http://www.blogger.com/atom/ns#" term="Cassandra"/><category scheme="http://www.blogger.com/atom/ns#" term="Couchbase"/><category scheme="http://www.blogger.com/atom/ns#" term="Kafka"/><category scheme="http://www.blogger.com/atom/ns#" term="log4net"/><category scheme="http://www.blogger.com/atom/ns#" term="MongoDB"/><category scheme="http://www.blogger.com/atom/ns#" term="NLog"/><category scheme="http://www.blogger.com/atom/ns#" term="RabbitMQ"/><category scheme="http://www.blogger.com/atom/ns#" term="RavenDB"/><category scheme="http://www.blogger.com/atom/ns#" term="Redis"/><category scheme="http://www.blogger.com/atom/ns#" term="SQLite"/><title type='text'>.NET Standard Adoption as of January 2017</title><content type='html'>&lt;p&gt;&lt;i&gt;Updated 2/16 to include Elasticsearch&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;As should be obviously from my recently blog posts, I have really been enjoying working with .NET Core. Clearly I am not alone, as a significant number of libraries have been porting over to the .NET Standard.&lt;/p&gt;

&lt;p&gt;Below is a list libraries that have added support for the .NET Standard, meaning that they should be able to run cross platform on both Windows and Linux.&lt;/p&gt;

&lt;p&gt;While I have not yet had the opportunity to try all of the libraries listed below, I have had great luck with the ones that I have tested, and I am simply ecstatic to see this list growing as fast as it is.&lt;/p&gt;

&lt;table&gt;

&lt;tr&gt;
&lt;th&gt;Technology&lt;/th&gt;
&lt;th&gt;NuGet Package&lt;/th&gt;
&lt;th&gt;.NET Standard Support&lt;/th&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Autofac&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.nuget.org/packages/Autofac/&quot; target=&quot;_blank&quot;&gt;Autofac&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Released for 1.1&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Cassandra&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.nuget.org/packages/CassandraCSharpDriver/&quot; target=&quot;_blank&quot;&gt;DataStax C# Driver for Apache Cassandra&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Released for 1.5&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Couchbase&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.nuget.org/packages/CouchbaseNetClient/&quot; target=&quot;_blank&quot;&gt;Couchbase SDK 2.0&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Beta for 1.5&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Elasticsearch&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.nuget.org/packages/Elasticsearch.Net/&quot; target=&quot;_blank&quot;&gt;Elasticsearch.Net&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Released for 1.3&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Kafka&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.nuget.org/packages/Confluent.Kafka/0.9.2-preview&quot; target=&quot;_blank&quot;&gt;Confluent.Kafka&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Preview for 1.3&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;log4net&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.nuget.org/packages/log4net/&quot; target=&quot;_blank&quot;&gt;Apache log4net&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Released for 1.3&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;MongoDB&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.nuget.org/packages/MongoDB.Driver/&quot; target=&quot;_blank&quot;&gt;MongoDB.Driver&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Released for 1.4&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;NLog&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.nuget.org/packages/NLog/5.0.0-beta05&quot; target=&quot;_blank&quot;&gt;NLog&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Beta for 1.3&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;RabbitMQ&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.nuget.org/packages/RabbitMQ.Client/5.0.0-pre2&quot; target=&quot;_blank&quot;&gt;RabbitMQ.Client&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Released for 1.5&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;RavenDB&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.nuget.org/packages/RavenDB.Client/3.5.3-patch-35187&quot; target=&quot;_blank&quot;&gt;RavenDB Client&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Released for 1.3&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Redis&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.nuget.org/packages/StackExchange.Redis/&quot; target=&quot;_blank&quot;&gt;StackExchange.Redis&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Released for 1.5&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;Sqlite&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.Sqlite/&quot; target=&quot;_blank&quot;&gt;Microsoft.EntityFrameworkCore.Sqlite&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Released for 1.3&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;WebSocket Client&lt;/td&gt;
&lt;td&gt;&lt;a href=&quot;https://www.nuget.org/packages/WebSocket4Net/&quot; target=&quot;_blank&quot;&gt;WebSocket4Net&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Released for 1.3&lt;/td&gt;
&lt;/tr&gt;

&lt;/table&gt;

&lt;p&gt;How have these libraries been working out for you? Is there a better option than what I have listed? Please leave a comment and let me know!&lt;/p&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/731677427134552933/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2017/01/net-standard-adoption-as-of-january-2017.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/731677427134552933'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/731677427134552933'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2017/01/net-standard-adoption-as-of-january-2017.html' title='.NET Standard Adoption as of January 2017'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-4801426475054416128</id><published>2017-01-29T16:06:00.000-08:00</published><updated>2017-01-29T16:06:37.202-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET"/><category scheme="http://www.blogger.com/atom/ns#" term="HttpClient"/><category scheme="http://www.blogger.com/atom/ns#" term="HttpContent"/><category scheme="http://www.blogger.com/atom/ns#" term="Json.Net"/><category scheme="http://www.blogger.com/atom/ns#" term="JsonContent"/><title type='text'>.NET JsonContent for HttpClient</title><content type='html'>&lt;img src=&quot;https://sites.google.com/site/tdupont750/json.png&quot; style=&quot;float:right; margin-left: 20px; margin-bottom: 20px; width: 125px;&quot;/&gt;

&lt;p&gt;.NET already comes with a nice collection of &lt;a href=&quot;https://github.com/dotnet/corefx/tree/master/src/System.Net.Http/src/System/Net/Http&quot; target=&quot;_blank&quot;&gt;HttpContent serializers&lt;/a&gt;, but it lacks a JsonContent type. A &lt;a href=&quot;http://stackoverflow.com/questions/23585919/send-json-via-post-in-c-sharp-and-receive-the-json-returned&quot; target=&quot;_blank&quot;&gt;common solution&lt;/a&gt; is to just serialize their payload to a JSON string and that insert that into an instance of StringContent. However, this means that you need to remember to set your headers, and it is a little bit inefficient because of how it creates multiple strings and buffers for each payload.&lt;/p&gt;

&lt;p&gt;I have create a simple implementation of JsonContent that uses &lt;a href=&quot;http://www.newtonsoft.com/json&quot; target=&quot;_blank&quot;&gt;Json.NET&lt;/a&gt; and &lt;a href=&quot;http://www.tomdupont.net/2016/12/object-pooling-and-memory-streams.html&quot; target=&quot;_blank&quot;&gt;pooled memory streams&lt;/a&gt;. The result is between 2% and 10% faster, and causes ~50% fewer garbage collections.&lt;/p&gt;

&lt;p&gt;Check out the implementation in &lt;a href=&quot;http://www.tomdupont.net/2016/10/introducing-tactnet.html&quot; target=&quot;_blank&quot;&gt;Tact.NET&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Json/Net/Http/JsonContent.cs&quot; target=&quot;_blank&quot;&gt;Source - JsonContent.cs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/tests/Tact.Tests/Net/Http/JsonContentTest.cs&quot; target=&quot;_blank&quot;&gt;Tests - JsonContentTests.cs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/4801426475054416128/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2017/01/net-jsoncontent-for-httpclient.html#comment-form' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/4801426475054416128'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/4801426475054416128'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2017/01/net-jsoncontent-for-httpclient.html' title='.NET JsonContent for HttpClient'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-760132552343597648</id><published>2016-12-31T14:17:00.000-08:00</published><updated>2017-01-01T14:20:11.476-08:00</updated><title type='text'>2016 Retrospective</title><content type='html'>&lt;img style=&quot;float:right; margin-left:15px; margin-bottom:15px; width:100px;&quot; src=&quot;https://sites.google.com/site/tdupont750/DotNetFoundation.png&quot;&gt;

&lt;h3&gt;.NET&lt;/h3&gt;

&lt;p&gt;It has been a great year for .NET development! A Visual Studio Community is fully featured, .NET Core has arrived, and everything is open source. Regarding .NET Core, I am really enjoying working with it, and I simply cannot wait to get deeper into the Linux world.&lt;/p&gt;

&lt;h3&gt;Blog&lt;/h3&gt;

&lt;p&gt;I finally had to downgrade from three posts per month to only two posts per month. Unfortunately writing quality blog posts tasks time, and that was not something that I had in great abundance this year. Fortunately, I do think that the majority of posts this year were very high quality, especially when you look at the most recent ones. I have been working a lot with performance optimization, and have really been enjoying profiling and digging deep into code to see exactly what it is doing and why.&lt;/p&gt;

&lt;img style=&quot;float:right; margin-left:15px; margin-bottom:15px; width:100px;&quot; src=&quot;https://sites.google.com/site/tdupont750/Tact_NET_M.png&quot;&gt;

&lt;h3&gt;Tact.NET&lt;/h3&gt;

&lt;p&gt;I am very happy to have launched &lt;a href=&quot;https://github.com/tdupont750/tact.net&quot; target=&quot;_blank&quot;&gt;Tact.NET&lt;/a&gt; this year! I have always really enjoyed creating frameworks, so rather than continue to write one off posts on this blog I decide to put all of my extracurricular worth together under one repository.  I am really enjoying making Tact, and I have every intention of continuing to grow it.&lt;/p&gt;

&lt;h3&gt;QQ Cast&lt;/h3&gt;

&lt;p&gt;Wow, the &lt;a href=&quot;http://www.qq-cast.com/&quot; target=&quot;_blank&quot;&gt;QQ Cast&lt;/a&gt; is back! We took a hiatus for the second half of 2015, but in 2016 we recorded 43 podcasts. Next week is actually going to be our 100th episode, be sure to check it out!

&lt;p&gt;Happy new year,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/760132552343597648/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/12/2016-retrospective.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/760132552343597648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/760132552343597648'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/12/2016-retrospective.html' title='2016 Retrospective'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-5075350639147411813</id><published>2016-12-30T13:58:00.000-08:00</published><updated>2017-01-04T18:05:17.051-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="MemoryStream"/><category scheme="http://www.blogger.com/atom/ns#" term="ObjectPool"/><category scheme="http://www.blogger.com/atom/ns#" term="Pooling"/><category scheme="http://www.blogger.com/atom/ns#" term="Tact"/><category scheme="http://www.blogger.com/atom/ns#" term="Tact.NET"/><title type='text'>Object Pooling and Memory Streams</title><content type='html'>&lt;p&gt;The theme of this year, which I will talk about in my 2016 retrospective, has been optimization. It&#39;s been a fun journey, and I have really enjoyed getting down and dirty with profiling garbage collection, using spin waits, and aggressive inlining.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;I want to end this year on a fun note: object pooling.&lt;/b&gt;&lt;/p&gt;

&lt;img style=&quot;float:right; margin-left: 15px; margin-bottom: 15px;&quot; src=&quot;https://sites.google.com/site/tdupont750/ObjectPool.png&quot; /&gt;

&lt;p&gt;A great use case for this would be making HTTP requests with serialized objects. When you serialize an object, and then place it in a &lt;a href=&quot;https://github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/System/Net/Http/HttpContent.cs&quot; target=&quot;_blank&quot;&gt;HttpContent&lt;/a&gt; object, you are probable creating several buffers (byte arrays) each time. For example, if you are using Newtonsoft to serialize an object and then adding that to a string content object for your request, then you are probably using more memory than you need. But that is getting ahead of ourselves...&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Come back next week for a blog post about efficient JSON Content serialization!&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;For now, let&#39;s focus on building an &lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact/Collections/ObjectPool.cs&quot; target=&quot;_blank&quot;&gt;object pool&lt;/a&gt;. Really all that we need is a preallocated array to store unused objects in, and then a super efficient thread safe data structure to pool (get and set) those objects.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;How does pooling memory streams help us?&lt;/b&gt;&lt;/p&gt;

When you create a &lt;a href=&quot;https://github.com/dotnet/corefx/blob/master/src/System.Runtime.Extensions/src/System/IO/MemoryStream.cs&quot; target=&quot;_blank&quot;&gt;MemoryStream&lt;/a&gt;, it creates a &lt;a href=&quot;https://github.com/dotnet/corefx/blob/master/src/System.Runtime.Extensions/src/System/IO/MemoryStream.cs#L52&quot; target=&quot;_blank&quot;&gt;byte array&lt;/a&gt;. As that byte array grows, the &lt;a href=&quot;https://github.com/dotnet/corefx/blob/master/src/System.Runtime.Extensions/src/System/IO/MemoryStream.cs#L281&quot; target=&quot;_blank&quot;&gt;memory stream resizes&lt;/a&gt; it by allocating a new larger array and then copying your bytes into it. This is inefficient not only because it creates new objects and throws the old ones away, but also because it has to do the leg work of copying the content each time it resizes.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;How can we reuse memory streams? Just set the length to zero!&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Internally this will just &lt;a href=&quot;https://github.com/dotnet/corefx/blob/master/src/System.Runtime.Extensions/src/System/IO/MemoryStream.cs#L604&quot; target=&quot;_blank&quot;&gt;set an index and empty the array&lt;/a&gt;, but the internal data structures will be preserved for future use. Thus, by putting memory streams into an object pool, we can drastically increase our efficiency.&lt;/p&gt;

&lt;p&gt;Here is a demo of using the &lt;a href=&quot;http://www.tomdupont.net/2016/10/introducing-tactnet.html&quot; target=&quot;_blank&quot;&gt;Tact.NET&lt;/a&gt; &lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact/Collections/ObjectPool.cs&quot; target=&quot;_blank&quot;&gt;ObjectPool&lt;/a&gt; to pool MemoryStreams...&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;[Fact]&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; MemoryStreamPoolDemo()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; pool = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ObjectPool&amp;lt;MemoryStream&amp;gt;(100, () =&amp;gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; MemoryStream()))&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; memoryStream1 = pool.Acquire();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        memoryStream1.SetLength(0);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Assert.Equal(0, memoryStream1.Capacity);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        memoryStream1.Write(&lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;byte&lt;/span&gt;[] {1, 0, 1, 0, 1}, 0, 5);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; array1 = memoryStream1.ToArray();&lt;/pre&gt;
&lt;pre&gt;        Assert.Equal(5, array1.Length);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Assert.Equal(1, array1.First());&lt;/pre&gt;
&lt;pre&gt;        Assert.Equal(1, array1.First());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        pool.Release(memoryStream1);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; memoryStream2 = pool.Acquire();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Assert.Same(memoryStream1, memoryStream2);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        memoryStream2.SetLength(0);&lt;/pre&gt;
&lt;pre&gt;        Assert.Equal(256, memoryStream2.Capacity);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        memoryStream2.Write(&lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;byte&lt;/span&gt;[] { 0, 1, 0 }, 0, 3);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; array2 = memoryStream2.ToArray();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Assert.Equal(3, array2.Length);&lt;/pre&gt;
&lt;pre&gt;        Assert.Equal(0, array2.First());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Assert.Equal(0, array2.First());&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/5075350639147411813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/12/object-pooling-and-memory-streams.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/5075350639147411813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/5075350639147411813'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/12/object-pooling-and-memory-streams.html' title='Object Pooling and Memory Streams'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-4341587783791108427</id><published>2016-11-27T12:27:00.000-08:00</published><updated>2016-11-27T12:34:25.691-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="Boxing"/><category scheme="http://www.blogger.com/atom/ns#" term="Class"/><category scheme="http://www.blogger.com/atom/ns#" term="Optimization"/><category scheme="http://www.blogger.com/atom/ns#" term="Performance"/><category scheme="http://www.blogger.com/atom/ns#" term="SortedDictionary"/><category scheme="http://www.blogger.com/atom/ns#" term="Struct"/><category scheme="http://www.blogger.com/atom/ns#" term="Tuple"/><category scheme="http://www.blogger.com/atom/ns#" term="Unboxing"/><title type='text'>The Performance Cost of Boxing in .NET</title><content type='html'>&lt;p&gt;I recently had to do some performance optimizations against a sorted dictionary that yielded some interesting results...&lt;/p&gt;

&lt;p&gt;Background: I am used to using Tuples a lot, simply because they are easy to use and normally quite efficient. Please remember that Tuples were changed from structs to classes back in .NET 4.0.&lt;/p&gt;

&lt;img style=&quot;float:right; margin-left:20px; margin-bottom:20px;&quot; src=&quot;https://sites.google.com/site/tdupont750/Struct_Optimization.PNG&quot;&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;Problem: A struct decreased performance!&lt;/h3&gt;

&lt;p&gt;I had a SortedDictionary that was using a Tuple as a key, so I thought &quot;hey, I&#39;ll just change that tuple to a struct and reduce the memory usage.&quot; ...bad news, that made performance WORSE!&lt;/p&gt;

&lt;p&gt;Why would using a struct make performance worse? It&#39;s actually quite simple and obvious when you think about it: it was causing comparisons to repeatedly box the primitive data structure, thus allocating more memory on the heap and triggering more garbage collections.&lt;/p&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;Solution: Use a struct with an IComparer.&lt;/h3&gt;

&lt;p&gt;I then created a custom struct and used that; it was must faster, but it was still causing boxing because of the non-generic IComparable interface. So finally I added a generic IComparer and passed that into my dictionary constructor; my dictionary then ran fast and efficient, causing a total of ZERO garbage collections!&lt;/p&gt;

&lt;p&gt;See for yourself:&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;&lt;img src=&quot;https://sites.google.com/site/tdupont750/Cost_of_Boxing.PNG&quot;&gt;&lt;/p&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;The Moral of the Story&lt;/h3&gt;

&lt;p&gt;Try to be aware of what default implementations are doing, and always remember that boxing to object can add up fast. Also, pay attention to the Visual Studio Diagnostics Tools window; it can be very informative!&lt;/p&gt;

&lt;p&gt;Here is how many lines of code it took to achieve a &lt;b&gt;5x performance increase&lt;/b&gt;:&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;struct&lt;/span&gt; MyStruct&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; MyStruct(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; i, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; s) { I = i; S = s; }&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; I;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; S;&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; MyStructComparer : IComparer&amp;lt;MyStruct&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; Compare(MyStruct x, MyStruct y)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; c = x.I.CompareTo(y.I);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; c != 0 ? c : StringComparer.Ordinal.Compare(x.S, y.S);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;Test Program&lt;/h3&gt;

&lt;p&gt;I have written some detailed comments in the Main function about what each test is doing and how it will affect performance. Let&#39;s take a look...&lt;/p&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Program&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Main(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;[] args)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// This is going to use the class implementation&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// of Tuple that was changed in .NET 4.0. It is&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// be inefficient for three reasons:&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// 1) It is allocating a new class on the heap &lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;//    for each and every key.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// 2) It is using the default object comparer&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;//    to check each item, causing inefficient &lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;//    comparisons and...&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// 3) Causing boxing of primitive values.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        ClassTupleAsKey();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Reset();&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// DURATION: 8,479 miliseconds&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// This is going to use the struct implementation&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// of Tuple that was available from .NET 2.0&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// until 4.0. It is even less efficiente than the&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// class tuple for both reasons listed above, and &lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// one new reason:&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// 4) The StructTuple itself will be boxed when&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;//    being passed between comparers, causing&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;//    even more garbage collections to occur!&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        StructTupleAsKey();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Reset();&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// DURATION: 8,880 miliseconds&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// Now we move to a custom struct implementation&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// for the dictionary key, but because we are using&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// a SortedDictionary we still need to implement&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// IComparable, which is not generic, and thus will&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// be slow for one reason:&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// 1) The struct itself will be boxed when being&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;//    passed between comparers.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        MyStructAsKey();&lt;/pre&gt;
&lt;pre&gt;        Reset();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// DURATION: 2,896 miliseconds&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// This is pretty much as fast as we can get; no&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// heap allocations, no boxing, fast comparisons.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        MyStructAsKeyWithCompare();&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// DURATION: 1,442 miliseconds&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Reset()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        GC.Collect();&lt;/pre&gt;
&lt;pre&gt;        Thread.Sleep(500);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; ClassTupleAsKey()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; dictionary = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; SortedDictionary&amp;lt;ClassTuple&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;&amp;gt;();&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; 1000000; i++)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; key = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ClassTuple&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;(i % 1000, i.ToString());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            dictionary.Add(key, i);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        sw.Stop();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Console.WriteLine(&lt;span class=&quot;str&quot;&gt;&quot;ClassTupleAsKey: &quot;&lt;/span&gt; + sw.ElapsedMilliseconds);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; StructTupleAsKey()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; dictionary = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; SortedDictionary&amp;lt;StructTuple&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;&amp;gt;();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; 1000000; i++)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; key = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; StructTuple&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;(i % 1000, i.ToString());&lt;/pre&gt;
&lt;pre&gt;            dictionary.Add(key, i);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        sw.Stop();&lt;/pre&gt;
&lt;pre&gt;        Console.WriteLine(&lt;span class=&quot;str&quot;&gt;&quot;StructTupleAsKey: &quot;&lt;/span&gt; + sw.ElapsedMilliseconds);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; MyStructAsKey()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; dictionary = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; SortedDictionary&amp;lt;MyStructA, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;&amp;gt;();&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; 1000000; i++)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; key = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; MyStructA(i % 1000, i.ToString());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            dictionary.Add(key, i);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        sw.Stop();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Console.WriteLine(&lt;span class=&quot;str&quot;&gt;&quot;StructAsKey: &quot;&lt;/span&gt; + sw.ElapsedMilliseconds);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; MyStructAsKeyWithCompare()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; dictionary = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; SortedDictionary&amp;lt;MyStructB, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;&amp;gt;(MyStructBComparer.Instance);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; 1000000; i++)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; key = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; MyStructB(i % 1000, i.ToString());&lt;/pre&gt;
&lt;pre&gt;            dictionary.Add(key, i);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        sw.Stop();&lt;/pre&gt;
&lt;pre&gt;        Console.WriteLine(&lt;span class=&quot;str&quot;&gt;&quot;StructAsKeyWithCompare: &quot;&lt;/span&gt; + sw.ElapsedMilliseconds);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ClassTuple&amp;lt;T1, T2&amp;gt; : IStructuralEquatable, IStructuralComparable, IComparable&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; T1 _item1;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; T2 _item2;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; T1 Item1 =&amp;gt; _item1;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; T2 Item2 =&amp;gt; _item2;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; ClassTuple(T1 item1, T2 item2)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            _item1 = item1;&lt;/pre&gt;
&lt;pre&gt;            _item2 = item2;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; Equals(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; obj)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; ((IStructuralEquatable) &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;).Equals(obj, EqualityComparer&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;&amp;gt;.Default);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; IStructuralEquatable.Equals(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; other, IEqualityComparer comparer)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; objTuple = other &lt;span class=&quot;kwrd&quot;&gt;as&lt;/span&gt; ClassTuple&amp;lt;T1, T2&amp;gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (objTuple == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; comparer.Equals(_item1, objTuple._item1) &amp;amp;&amp;amp; comparer.Equals(_item2, objTuple._item2);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; IComparable.CompareTo(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; obj)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; ((IStructuralComparable) &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;).CompareTo(obj, Comparer&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;&amp;gt;.Default);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; IStructuralComparable.CompareTo(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; other, IComparer comparer)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (other == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;) &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; 1;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; objTuple = other &lt;span class=&quot;kwrd&quot;&gt;as&lt;/span&gt; ClassTuple&amp;lt;T1, T2&amp;gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (objTuple == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ArgumentException(&lt;span class=&quot;str&quot;&gt;&quot;ArgumentException_TupleIncorrectType&quot;&lt;/span&gt;, nameof(other));&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; c = comparer.Compare(_item1, objTuple._item1);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; c != 0 ? c : comparer.Compare(_item2, objTuple._item2);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; GetHashCode()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; ((IStructuralEquatable) &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;).GetHashCode(EqualityComparer&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;&amp;gt;.Default);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; IStructuralEquatable.GetHashCode(IEqualityComparer comparer)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; CombineHashCodes(comparer.GetHashCode(_item1), comparer.GetHashCode(_item2));&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; CombineHashCodes(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; h1, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; h2)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; ((h1 &amp;lt;&amp;lt; 5) + h1) ^ h2;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;struct&lt;/span&gt; StructTuple&amp;lt;T1, T2&amp;gt; : IStructuralEquatable, IStructuralComparable, IComparable&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; T1 _item1;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; T2 _item2;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; T1 Item1 =&amp;gt; _item1;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; T2 Item2 =&amp;gt; _item2;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; StructTuple(T1 item1, T2 item2)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            _item1 = item1;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            _item2 = item2;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; Equals(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; obj)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; ((IStructuralEquatable) &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;).Equals(obj, EqualityComparer&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;&amp;gt;.Default);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; IStructuralEquatable.Equals(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; other, IEqualityComparer comparer)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!(other &lt;span class=&quot;kwrd&quot;&gt;is&lt;/span&gt; StructTuple&amp;lt;T1, T2&amp;gt;)) &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; objTuple = (StructTuple&amp;lt;T1, T2&amp;gt;) other;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; comparer.Equals(_item1, objTuple._item1) &amp;amp;&amp;amp; comparer.Equals(_item2, objTuple._item2);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; IComparable.CompareTo(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; obj)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; ((IStructuralComparable) &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;).CompareTo(obj, Comparer&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;&amp;gt;.Default);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; IStructuralComparable.CompareTo(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; other, IComparer comparer)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; objTuple = (StructTuple&amp;lt;T1, T2&amp;gt;) other;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; c = comparer.Compare(_item1, objTuple._item1);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; c != 0 ? c : comparer.Compare(_item2, objTuple._item2);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; GetHashCode()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; ((IStructuralEquatable) &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt;).GetHashCode(EqualityComparer&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;&amp;gt;.Default);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; IStructuralEquatable.GetHashCode(IEqualityComparer comparer)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; CombineHashCodes(comparer.GetHashCode(_item1), comparer.GetHashCode(_item2));&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; CombineHashCodes(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; h1, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; h2)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; ((h1 &amp;lt;&amp;lt; 5) + h1) ^ h2;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;struct&lt;/span&gt; MyStructA : IComparable&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; MyStructA(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; i, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; s)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            I = i;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            S = s;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; I;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; S;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; CompareTo(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; obj)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; y = (MyStructA) obj;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; c = I.CompareTo(y.I);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; c != 0 ? c : StringComparer.Ordinal.Compare(S, y.S);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;struct&lt;/span&gt; MyStructB&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; MyStructB(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; i, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; s)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            I = i;&lt;/pre&gt;
&lt;pre&gt;            S = s;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; I;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; S;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; MyStructBComparer : IComparer&amp;lt;MyStructB&amp;gt;&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; MyStructBComparer Instance = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; MyStructBComparer();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; Compare(MyStructB x, MyStructB y)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; c = x.I.CompareTo(y.I);&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; c != 0 ? c : StringComparer.Ordinal.Compare(x.S, y.S);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/4341587783791108427/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/11/the-performance-cost-of-boxing-in-net.html#comment-form' title='97 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/4341587783791108427'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/4341587783791108427'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/11/the-performance-cost-of-boxing-in-net.html' title='The Performance Cost of Boxing in .NET'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>97</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-3612728231195869394</id><published>2016-11-26T18:40:00.001-08:00</published><updated>2016-11-26T18:40:34.783-08:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term=".NET Core"/><category scheme="http://www.blogger.com/atom/ns#" term="Delegate"/><category scheme="http://www.blogger.com/atom/ns#" term="DynamicInvoke"/><category scheme="http://www.blogger.com/atom/ns#" term="Invoke"/><category scheme="http://www.blogger.com/atom/ns#" term="Performance"/><category scheme="http://www.blogger.com/atom/ns#" term="Reflection"/><title type='text'>10x faster than Delegate.DynamicInvoke</title><content type='html'>&lt;p&gt;This is a follow up to my previous blog posts, &lt;a href=&quot;http://www.tomdupont.net/2016/08/optimizing-dynamic-method-invokes-in-net.html&quot; target=&quot;_blank&quot;&gt;Optimizing Dynamic Method Invokes in .NET&lt;/a&gt;, and &lt;a href=&quot;http://www.tomdupont.net/2016/08/dynamically-invoke-methods-quickly-with.html&quot; target=&quot;_blank&quot;&gt;Dynamically Invoke Methods Quickly, with InvokeHelpers.EfficientInvoke&lt;/a&gt;. Basically, I have re-implemented this for &lt;a href=&quot;http://www.tomdupont.net/2016/10/introducing-tactnet.html&quot; target=&quot;_blank&quot;&gt;Tact.NET&lt;/a&gt; in a way that makes it smaller, faster, and compatible with the .NET Standard.&lt;/p&gt;

&lt;p style=&quot;text-align:center&quot;&gt;&lt;img style=&quot;float:right; width:450px;&quot; src=&quot;https://sites.google.com/site/tdupont750/Efficient_Invoke_Performance.PNG&quot;&gt;&lt;/p&gt;

&lt;p&gt;So, how much faster is this new way of doing things? EfficientInvoker.Invoke is over &lt;b&gt;10x faster&lt;/b&gt; than Delegate.DynamicInvoke, and &lt;b&gt;10x faster&lt;/b&gt; than MethodInfo.Invoke.

&lt;p&gt;Check out the source on GitHub:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact/Reflection/EfficientInvoker.cs&quot; target=&quot;_blank&quot;&gt;EfficientInvoker.cs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/tests/Tact.Tests/Reflection/EfficientInvokerTests.cs&quot; target=&quot;_blank&quot;&gt;EfficientInvokerTests.cs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;Simple Explanation&lt;/h3&gt;

&lt;p&gt;Here is an example of a method and a class that we might want to invoke dynamically...&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Tester&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; AreEqual(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; a, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; b)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; a == b;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;...and then here is the code that the EfficientInvoker will generate at runtime to call that method:&lt;/p&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; GeneratedFunction(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; target, &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;[] args)&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;)((Tester)target).AreEqual((&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;)args[0], (&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;)args[1]);&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;See, it&#39;s simple!&lt;/p&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;Sample Tests&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; EfficientInvokerTest&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; DelegateInvoke()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; del = (Delegate) &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Func&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt;&amp;gt;((a, b) =&amp;gt; a == b);&lt;/pre&gt;
&lt;pre&gt;            &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// Standard slow way&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; result1 = (&lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt;)del.DynamicInvoke(1, 2);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Assert.False(result1);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// New 10x faster way&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; invoker = del.GetInvoker();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; result2 = (&lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt;)invoker.Invoke(del, 1, 2);&lt;/pre&gt;
&lt;pre&gt;        Assert.False(result2);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;    &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; MethodInvoke()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; tester = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Tester();&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; type = tester.GetType();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// Standard slow way&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; methodInfo = type.GetTypeInfo().GetMethod(&lt;span class=&quot;str&quot;&gt;&quot;AreEqual&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; result1 = (&lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt;) methodInfo.Invoke(tester, &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;[] {1, 2});&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Assert.False(result1);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// New 10x faster way&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; invoker = type.GetMethodInvoker(&lt;span class=&quot;str&quot;&gt;&quot;AreEqual&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; result2 = (&lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt;) invoker.Invoke(tester, 1, 2);&lt;/pre&gt;
&lt;pre&gt;        Assert.False(result2);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;    &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; Tester&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; AreEqual(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; a, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; b)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; a == b;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/3612728231195869394/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/11/10x-faster-than-delegatedynamicinvoke.html#comment-form' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/3612728231195869394'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/3612728231195869394'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/11/10x-faster-than-delegatedynamicinvoke.html' title='10x faster than Delegate.DynamicInvoke'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-1378591545206240288</id><published>2016-10-31T18:00:00.000-07:00</published><updated>2016-10-31T22:39:34.848-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET Core"/><category scheme="http://www.blogger.com/atom/ns#" term=".NET Standard"/><category scheme="http://www.blogger.com/atom/ns#" term="Dependency Injection"/><category scheme="http://www.blogger.com/atom/ns#" term="DI"/><category scheme="http://www.blogger.com/atom/ns#" term="Inversion of Control"/><category scheme="http://www.blogger.com/atom/ns#" term="IOC"/><category scheme="http://www.blogger.com/atom/ns#" term="Tact"/><category scheme="http://www.blogger.com/atom/ns#" term="Tact.NET"/><category scheme="http://www.blogger.com/atom/ns#" term="Unity"/><title type='text'>IOC Container for Tact.NET</title><content type='html'>&lt;img style=&quot;float:right;margin-left:20px;margin-bottom:20px;&quot; src=&quot;http://sites.google.com/site/tdupont750/microsoft_patterns_practices.gif&quot;&gt;

&lt;p&gt;&lt;a href=&quot;http://docs.autofac.org/en/latest/integration/aspnetcore.html&quot; target=&quot;_blank&quot;&gt;Autofac&lt;/a&gt; now supports .NET Core, but other IOC frameworks such as &lt;a href=&quot;http://www.ninject.org/&quot; target=&quot;_blank&quot;&gt;Ninject&lt;/a&gt; and &lt;a href=&quot;https://msdn.microsoft.com/library/ff647202.aspx&quot; taret=&quot;_blank&quot;&gt;Unity&lt;/a&gt; have yet to port over. While I was looking into IOC frameworks for .NET Core, I had a bad idea...I, for fun, wrote my own &lt;a href=&quot;https://github.com/tdupont750/tact.net/tree/master/src/Tact.Core/Practices&quot; target=&quot;_blank&quot;&gt;Container&lt;/a&gt; in &lt;a href=&quot;https://github.com/tdupont750/tact.net/&quot; target=&quot;_blank&quot;&gt;Tact.NET&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;So, why did I do this? Honestly, it was just a fun academic exercise! I do think that this is a pretty good container, and I intend to use it in some of my personal projects. Would I recommend that YOU use this? Probably not yet, but I would invite you take a look and offer feedback!&lt;/p&gt;

&lt;h3&gt;Container Design&lt;/h3&gt;

&lt;p&gt;I have broken the container into two interfaces: &lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/IContainer.cs&quot; target=&quot;_blank&quot;&gt;IContainer&lt;/a&gt; for registration, and &lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/IResolver.cs&quot; target=&quot;_blank&quot;&gt;IResolver&lt;/a&gt; for consumption. There is a abstract class, &lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/Base/ContainerBase.cs&quot; target=&quot;_blank&quot;&gt;ContainerBase&lt;/a&gt;, that can be inherited to easily create a container that matches other frameworks; for example, I intend to create a &lt;a href=&quot;https://www.asp.net/mvc/overview/older-versions/hands-on-labs/aspnet-mvc-4-dependency-injection&quot; target=&quot;_blank&quot;&gt;IDependencyResolver for ASP.NET&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You may notice that the IContainer does not have any &lt;a href=&quot;http://www.tomdupont.net/2013/12/undestanding-unity-lifetime-managers.html&quot; target=&quot;_blank&quot;&gt;lifetime management&lt;/a&gt; methods, that is because ALL of them are implemented as &lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Extensions/ContainerExtensions.cs&quot; target=&quot;_blank&quot;&gt;extension methods&lt;/a&gt;...&lt;/p&gt;

&lt;h3&gt;Registrations&lt;/h3&gt;

&lt;p&gt;To create a new lifetime manager you have to implement the &lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/Registration/IRegistration.cs&quot; target=&quot;_blank&quot;&gt;IRegistration&lt;/a&gt; interface. There are already implementations for quite a few:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/Registration/Implementation/InstanceRegistration.cs&quot; target=&quot;_blank&quot;&gt;InstanceRegistration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/Registration/Implementation/PerResolveRegistration.cs&quot; target=&quot;_blank&quot;&gt;PerResolveRegistration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/Registration/Implementation/PerScopeRegistration.cs&quot; target=&quot;_blank&quot;&gt;PerScopeRegistration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/Registration/Implementation/SingletonRegistration.cs&quot; target=&quot;_blank&quot;&gt;SingletonRegistration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/Registration/Implementation/TransientRegistration.cs&quot; target=&quot;_blank&quot;&gt;TransientRegistration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Resolution Handlers&lt;/h3&gt;

&lt;p&gt;The last part of the container is the &lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/ResolutionHandlers/IResolutionHandler.cs&quot; target=&quot;_blank&quot;&gt;IResolutionHandler&lt;/a&gt; interface. These resolution handlers are used when an exact registration match is not found during dependency resolution. For example, the &lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/ResolutionHandlers/Implementation/EnumerableResolutionHandler.cs&quot; target=&quot;_blank&quot;&gt;EnumerableResolutionHandler&lt;/a&gt; will use ResolveAll to get a collection of whatever type is being requested. Another very different example, the &lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/ResolutionHandlers/Implementation/ThrowOnFailResolutionHandler.cs&quot; target=&quot;_blank&quot;&gt;ThrowOnFailResolutionHandler&lt;/a&gt; will cause an exception to be thrown when no match can be found.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/ResolutionHandlers/Implementation/EnumerableResolutionHandler.cs&quot; target=&quot;_blank&quot;&gt;EnumerableResolutionHandler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/ResolutionHandlers/Implementation/FuncResolutionHandler.cs&quot; target=&quot;_blank&quot;&gt;FuncResolutionHandler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/ResolutionHandlers/Implementation/LazyResolutionHandler.cs&quot; target=&quot;_blank&quot;&gt;LazyResolutionHandler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/ResolutionHandlers/Implementation/ThrowOnFailResolutionHandler.cs&quot; target=&quot;_blank&quot;&gt;ThrowOnFailResolutionHandler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Practices/ResolutionHandlers/Implementation/UnregisteredResolutionHandler.cs&quot; target=&quot;_blank&quot;&gt;UnregisteredResolutionHandler&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I think that is a pretty good start, but I am hoping that this will continue to grow with time.&lt;/p&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/1378591545206240288/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/10/ioc-container-for-tactnet.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/1378591545206240288'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/1378591545206240288'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/10/ioc-container-for-tactnet.html' title='IOC Container for Tact.NET'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-1644851859117655201</id><published>2016-10-31T08:30:00.000-07:00</published><updated>2016-10-31T08:30:31.854-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term=".NET Core"/><category scheme="http://www.blogger.com/atom/ns#" term="Tact"/><category scheme="http://www.blogger.com/atom/ns#" term="Tact.NET"/><title type='text'>Introducing Tact.NET</title><content type='html'>&lt;img style=&quot;float:right; margin-left:20px; margin-bottom:20px;&quot; src=&quot;https://sites.google.com/site/tdupont750/DotNetFoundation.png&quot; /&gt;

&lt;p&gt;I have decided to create a project to consolidate all of the utilities that I have authored over the years on this blog...&lt;/p&gt;

&lt;p style=&quot;text-align: center;&quot;&gt;&lt;a href=&quot;https://github.com/tdupont750/tact.net&quot; target=&quot;_blank&quot;&gt;&lt;b&gt;Tact.NET&lt;/b&gt; - A tactful collection of utilities for .NET development.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I believe that this will give me the opportunity to update old code more often, as well as develop new utilities faster. For example, the there is already an &lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Diagnostics/ILog.cs&quot; target=&quot;_blank&quot;&gt;ILog&lt;/a&gt; interface that &lt;a href=&quot;https://github.com/tdupont750/tact.net/blob/master/src/Tact.Core/Diagnostics/Log.generated.tt#L62&quot; target=&quot;_blank&quot;&gt;optimizes&lt;/a&gt; (thank you, Jeremy) the &lt;a href=&quot;http://www.tomdupont.net/2016/05/common-logging-extensions-with-caller.html&quot; target=&quot;_blank&quot;&gt;Caller Information Extensions&lt;/a&gt; I wrote about about back in May.&lt;/p&gt;

&lt;p&gt;Everything that I add to this project will be build for the .NET Standard Library, and should support .NET Core on all platforms. Expect to see NuGet packages soon, and hopefully many more blog posts to come.&lt;/p&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;



</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/1644851859117655201/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/10/introducing-tactnet.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/1644851859117655201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/1644851859117655201'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/10/introducing-tactnet.html' title='Introducing Tact.NET'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-1933475826815089442</id><published>2016-09-30T09:06:00.000-07:00</published><updated>2016-10-02T09:14:09.417-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET"/><category scheme="http://www.blogger.com/atom/ns#" term="Fleck"/><category scheme="http://www.blogger.com/atom/ns#" term="Owin"/><category scheme="http://www.blogger.com/atom/ns#" term="WebSocket Server"/><category scheme="http://www.blogger.com/atom/ns#" term="WebSockets"/><title type='text'>Host HTTP and WebSockets on the Same Port in ASP.NET</title><content type='html'>
&lt;p&gt;How do you support WebSocket connections on  the same port as your HTTP server in .NET? It turns out that this is not that hard, and you even have several choices to do so...&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;&lt;img src=&quot;https://sites.google.com/site/tdupont750/html5-websockets.jpg&quot;&gt;&lt;/p&gt;

&lt;h3&gt;Option 1: TCP Proxy&lt;/h3&gt;

&lt;p&gt;You could use a TCP proxy port to divide traffic between the two targets. For example, all traffic would come in to port 80, but then HTTP traffic would be routed internally to 8001 and WS traffic to 8002. This is useful because it would allow you to use multiple technologies (in the example on their site, both NancyFX and Fleck) to host your web servers.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/lifeemotions/websocketproxy&quot; target=&quot;_blank&quot;&gt;github.com/lifeemotions/websocketproxy&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;h3&gt;Option 2: SignalR&lt;/h3&gt;

&lt;p&gt;SignalR is great because of all the backwards compatibility that it supports for both the server and client. However, it is not the most lightweight framework. If you choose to use it, then it will absolutely support both HTTP and WS.

&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://www.asp.net/signalr&quot; target=&quot;_blank&quot;&gt;asp.net/signalr&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;h3&gt;Option 3: Owin.WebSocket &lt;i&gt;*My Favorite*&lt;/i&gt;&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://owin.org/spec/extensions/owin-WebSocket-Extension-v0.4.0.htm&quot; target=&quot;_blank&quot;&gt;Owin supports WebSockets&lt;/a&gt;, and that is exactly what SignalR uses to host its WS connections. The awesome &lt;a href=&quot;https://github.com/bryceg&quot; target=&quot;_blank&quot;&gt;Mr. Bryce Godfrey&lt;/a&gt; extracted the Owin code from SignalR into a much smaller library called Owin.WebSocket.

&lt;p&gt;The ONLY thing that I did not like about this implementation was that is uses inheritance to define endpoints, whereas I much prefer the ability to use delegates and lambdas. Because of this, I created &lt;a href=&quot;https://github.com/tdupont750/Owin.WebSocket/tree/master/src/Owin.WebSocket.Fleck&quot; target=&quot;_blank&quot;&gt;Owin.WebSocket.Fleck&lt;/a&gt;, which allows you to use the Fleck API to map your WebSockets to an Owin context. A &lt;a href=&quot;https://github.com/bryceg/Owin.WebSocket/pull/20&quot; target=&quot;_blank&quot;&gt;pull request&lt;/a&gt; is open to merge this into the main repository.&lt;/p&gt;

&lt;ul&gt;&lt;li&gt;&lt;a href=&quot;https://github.com/bryceg/Owin.WebSocket&quot; target=&quot;_blank&quot;&gt;github.com/bryceg/Owin.WebSocket&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/1933475826815089442/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/09/host-http-and-websockets-on-same-port.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/1933475826815089442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/1933475826815089442'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/09/host-http-and-websockets-on-same-port.html' title='Host HTTP and WebSockets on the Same Port in ASP.NET'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-4582495264437642076</id><published>2016-09-25T11:05:00.001-07:00</published><updated>2016-09-25T22:04:40.376-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="Async"/><category scheme="http://www.blogger.com/atom/ns#" term="Concurrency"/><category scheme="http://www.blogger.com/atom/ns#" term="ConcurrentQueue"/><title type='text'>.NET Asynchronous Parallel Batch Processor</title><content type='html'>&lt;p&gt;Last year, &lt;a href=&quot;http://www.tomdupont.net/2015/06/net-asynchronous-batch-processor.html&quot; target=&quot;_blank&quot;&gt;I wrote about&lt;/a&gt; how to handle dynamically sized batches of data in an asynchronous manner. That original implementation used an abstract base class, and only supported a single background processing thread. I recently updated that implementation to support lambdas rather than requiring inheritance, and support a dynamic number of background threads.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;...basically, this is a ConcurrentQueue that supports taking a lambda and thread count to asynchronously process enqueued items.&lt;/i&gt;&lt;/p&gt; 

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;Unit Tests&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ParallelProcessorTests&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    [Fact]&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; async Task NoDisposeTimeout()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; results = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ConcurrentQueue&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;&amp;gt;();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; processor = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ParallelProcessor&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;&amp;gt;(2, async (i, token) =&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            await Task.Delay(200, token).ConfigureAwait(&lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            results.Enqueue(i);&lt;/pre&gt;
&lt;pre&gt;        }, disposeTimeoutMs: 0))&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            processor.Enqueue(1);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            processor.Enqueue(2);&lt;/pre&gt;
&lt;pre&gt;            processor.Enqueue(3);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            processor.Enqueue(4);&lt;/pre&gt;
&lt;pre&gt;            processor.Enqueue(5);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            await Task.Delay(300).ConfigureAwait(&lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Assert.Equal(2, results.Count);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    [Fact]&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; MaxParallelizationLimit()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; parallelism = 3;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; results = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ConcurrentQueue&amp;lt;Tuple&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;&amp;gt;&amp;gt;();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; active = 0;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; processor = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ParallelProcessor&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;&amp;gt;(parallelism, async (i, token) =&amp;gt;&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            Interlocked.Increment(&lt;span class=&quot;kwrd&quot;&gt;ref&lt;/span&gt; active);&lt;/pre&gt;
&lt;pre&gt;            await Task.Delay(200, token).ConfigureAwait(&lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; currentActive = Interlocked.Decrement(&lt;span class=&quot;kwrd&quot;&gt;ref&lt;/span&gt; active) + 1;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; tuple = Tuple.Create(currentActive, i);&lt;/pre&gt;
&lt;pre&gt;            results.Enqueue(tuple);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }))&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            processor.Enqueue(1);&lt;/pre&gt;
&lt;pre&gt;            processor.Enqueue(2);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            processor.Enqueue(3);&lt;/pre&gt;
&lt;pre&gt;            processor.Enqueue(4);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            processor.Enqueue(5);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        Assert.Equal(5, results.Count);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; maxParallelism = results.Max(t =&amp;gt; t.Item1);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Assert.Equal(parallelism, maxParallelism);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    [Fact]&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; BatchProcessor()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; results = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; List&amp;lt;Tuple&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;long&lt;/span&gt;, List&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;&amp;gt;&amp;gt;&amp;gt;();&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; processor = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; BatchParallelProcessor&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;&amp;gt;(1, 2, async (ints, token) =&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            await Task.Delay(100, token).ConfigureAwait(&lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; tuple = Tuple.Create(sw.ElapsedMilliseconds, ints);&lt;/pre&gt;
&lt;pre&gt;            results.Add(tuple);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }))&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            processor.Enqueue(1);&lt;/pre&gt;
&lt;pre&gt;            processor.Enqueue(2);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            processor.Enqueue(3);&lt;/pre&gt;
&lt;pre&gt;            processor.Enqueue(4);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            processor.Enqueue(5);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        Assert.Equal(3, results.Count);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        Assert.Equal(2, results[0].Item2.Count);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Assert.Equal(1, results[0].Item2[0]);&lt;/pre&gt;
&lt;pre&gt;        Assert.Equal(2, results[0].Item2[1]);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        Assert.True(results[0].Item1 &amp;lt; results[1].Item1);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Assert.Equal(2, results[1].Item2.Count);&lt;/pre&gt;
&lt;pre&gt;        Assert.Equal(3, results[1].Item2[0]);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Assert.Equal(4, results[1].Item2[1]);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Assert.True(results[1].Item1 &amp;lt; results[2].Item1);&lt;/pre&gt;
&lt;pre&gt;        Assert.Equal(1, results[2].Item2.Count);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Assert.Equal(5, results[2].Item2[0]);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;ParallelProcessor&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;sealed&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ParallelProcessor&amp;lt;T&amp;gt; : ProcessorBase&amp;lt;T&amp;gt;&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; Func&amp;lt;T, CancellationToken, Task&amp;gt; _processHandler;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; Action&amp;lt;T, Exception&amp;gt; _exceptionHandler;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; ParallelProcessor(&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; maxParallelization, &lt;/pre&gt;
&lt;pre&gt;        Func&amp;lt;T, CancellationToken, Task&amp;gt; processHandler, &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Action&amp;lt;T, Exception&amp;gt; exceptionHandler = &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;,&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; disposeTimeoutMs = 30000,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;? maxQueueSize = &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;        : &lt;span class=&quot;kwrd&quot;&gt;base&lt;/span&gt;(maxParallelization, disposeTimeoutMs, maxQueueSize)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (maxParallelization &amp;lt; 1)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ArgumentException(&lt;/pre&gt;
&lt;pre&gt;                $&lt;span class=&quot;str&quot;&gt;&quot;{nameof(maxParallelization)} is required&quot;&lt;/span&gt;,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                nameof(maxParallelization));&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _processHandler = processHandler;&lt;/pre&gt;
&lt;pre&gt;        _exceptionHandler = exceptionHandler;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; async Task ProcessLoopAsync()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        T item;&lt;/pre&gt;
&lt;pre&gt;        while (!CancelSource.IsCancellationRequested &amp;amp;&amp;amp; Queue.TryDequeue(&lt;span class=&quot;kwrd&quot;&gt;out&lt;/span&gt; item))&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;try&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            {&lt;/pre&gt;
&lt;pre&gt;                await _processHandler(item, CancelSource.Token).ConfigureAwait(&lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            }&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;catch&lt;/span&gt; (TaskCanceledException) when (CancelSource.IsCancellationRequested)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            {&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;rem&quot;&gt;// Cancellation was requested, ignore and exit.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;catch&lt;/span&gt; (Exception ex)&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                _exceptionHandler?.Invoke(item, ex);&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;BatchParallelProcessor&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;sealed&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; BatchParallelProcessor&amp;lt;T&amp;gt; : ProcessorBase&amp;lt;T&amp;gt;&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; _batchSize;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; Func&amp;lt;List&amp;lt;T&amp;gt;, CancellationToken, Task&amp;gt; _processHandler;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; Action&amp;lt;List&amp;lt;T&amp;gt;, Exception&amp;gt; _exceptionHandler;&lt;/pre&gt;
&lt;pre&gt;        &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; BatchParallelProcessor(&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; maxParallelization,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; batchSize,&lt;/pre&gt;
&lt;pre&gt;        Func&amp;lt;List&amp;lt;T&amp;gt;, CancellationToken, Task&amp;gt; processHandler,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Action&amp;lt;List&amp;lt;T&amp;gt;, Exception&amp;gt; exceptionHandler = &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;,&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; disposeTimeoutMs = 30000,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;? maxQueueSize = &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;)&lt;/pre&gt;
&lt;pre&gt;        : &lt;span class=&quot;kwrd&quot;&gt;base&lt;/span&gt;(maxParallelization, disposeTimeoutMs, maxQueueSize)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (batchSize &amp;lt; 1)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ArgumentException(&lt;/pre&gt;
&lt;pre&gt;                $&lt;span class=&quot;str&quot;&gt;&quot;{nameof(batchSize)} is required&quot;&lt;/span&gt;,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                nameof(batchSize));&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _batchSize = batchSize;&lt;/pre&gt;
&lt;pre&gt;        _processHandler = processHandler;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _exceptionHandler = exceptionHandler;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; async Task ProcessLoopAsync()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        while (!CancelSource.IsCancellationRequested)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; count = Math.Min(_batchSize, Queue.Count + 1);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; list = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; List&amp;lt;T&amp;gt;(count);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            T item;&lt;/pre&gt;
&lt;pre&gt;            while (list.Count &amp;lt; _batchSize &amp;amp;&amp;amp; Queue.TryDequeue(&lt;span class=&quot;kwrd&quot;&gt;out&lt;/span&gt; item))&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                list.Add(item);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (list.Count == 0)&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;try&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            {&lt;/pre&gt;
&lt;pre&gt;                await _processHandler(list, CancelSource.Token).ConfigureAwait(&lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            }&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;catch&lt;/span&gt; (TaskCanceledException) when (CancelSource.IsCancellationRequested)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            {&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;rem&quot;&gt;// Cancellation was requested, ignore and exit.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;catch&lt;/span&gt; (Exception ex)&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                _exceptionHandler?.Invoke(list, ex);&lt;/pre&gt;
&lt;pre&gt;            }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;ProcessorBase&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; ProcessorBase&amp;lt;T&amp;gt; : IDisposable&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; ConcurrentQueue&amp;lt;T&amp;gt; Queue = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ConcurrentQueue&amp;lt;T&amp;gt;();&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; CancellationTokenSource CancelSource = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; CancellationTokenSource();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; _lock = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; Task[] _tasks;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; _disposeTimeoutMs;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;? _maxQueueSize;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; _isDisposed;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;protected&lt;/span&gt; ProcessorBase(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; maxParallelization, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; disposeTimeoutMs, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;? maxQueueSize)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _tasks = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Task[maxParallelization];&lt;/pre&gt;
&lt;pre&gt;        _disposeTimeoutMs = disposeTimeoutMs;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _maxQueueSize = maxQueueSize;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Dispose()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (_isDisposed)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _isDisposed = &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (_disposeTimeoutMs &amp;gt; 0)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; tasks = _tasks.Where(t =&amp;gt; t != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;).ToArray();&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; allTask = Task.WhenAll(tasks);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; delayTask = Task.Delay(_disposeTimeoutMs);&lt;/pre&gt;
&lt;pre&gt;            Task.WaitAny(allTask, delayTask);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        CancelSource.Cancel();&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Enqueue(T item)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (_isDisposed)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; InvalidOperationException(&lt;span class=&quot;str&quot;&gt;&quot;Cancellation has been requested&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (_maxQueueSize.HasValue &amp;amp;&amp;amp; Queue.Count &amp;gt;= _maxQueueSize)&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; InvalidOperationException(&lt;span class=&quot;str&quot;&gt;&quot;Queue is full&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        Queue.Enqueue(item);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        TryStartProcessLoop();&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; TryEnqueue(T item)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (_isDisposed)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (_maxQueueSize.HasValue &amp;amp;&amp;amp; Queue.Count &amp;gt;= _maxQueueSize)&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        Queue.Enqueue(item);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        TryStartProcessLoop();&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;abstract&lt;/span&gt; Task ProcessLoopAsync();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; TryStartProcessLoop()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// Another thread is in the lock, bail out.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!Monitor.TryEnter(_lock))&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// Create task outside of lock to ensure that we attach the&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// continue without while another thread can be in the block.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Task task;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;try&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;rem&quot;&gt;// If cancellation has been requested, do not start.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (CancelSource.IsCancellationRequested)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;rem&quot;&gt;// If the queue is empty, do not start.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (Queue.Count == 0)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; freeIndex = 0;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; activeCount = 0;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;rem&quot;&gt;// Find last free index&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; _tasks.Length; i++)&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (_tasks[i] == &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt; || _tasks[i].IsCompleted)&lt;/pre&gt;
&lt;pre&gt;                    freeIndex = i;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;else&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;                    activeCount++;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;rem&quot;&gt;// All tasks are active, do not start.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (activeCount == _tasks.Length)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;rem&quot;&gt;// Only one in queue, at least one thread is active, do not start additional thread.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (activeCount &amp;gt; 0 &amp;amp;&amp;amp; Queue.Count &amp;lt;= 1)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;rem&quot;&gt;// Start a new task to process the queue.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            task = _tasks[freeIndex] = Task.Run(ProcessLoopAsync, CancelSource.Token);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;finally&lt;/span&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            Monitor.Exit(_lock);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// When the process queue task completes, check to see if&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// the queue has been populated again and needs to restart.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        task.ContinueWith(t =&amp;gt; TryStartProcessLoop());&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;
</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/4582495264437642076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/09/net-asynchronous-parallel-batch.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/4582495264437642076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/4582495264437642076'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/09/net-asynchronous-parallel-batch.html' title='.NET Asynchronous Parallel Batch Processor'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-6112842309461345254</id><published>2016-08-21T12:28:00.000-07:00</published><updated>2016-08-21T12:28:57.160-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="Delegate"/><category scheme="http://www.blogger.com/atom/ns#" term="Dynamic"/><category scheme="http://www.blogger.com/atom/ns#" term="Invoke"/><category scheme="http://www.blogger.com/atom/ns#" term="Performance"/><category scheme="http://www.blogger.com/atom/ns#" term="Reflection"/><title type='text'>Dynamically Invoke Methods Quickly, with InvokeHelpers.EfficientInvoke</title><content type='html'>&lt;img src=&quot;http://devstickers.com/assets/img/pro/2p4i.png&quot; style=&quot;float:right; width: 200px; margin-left: 20px; margin-bottom: 20px;&quot;&gt;

&lt;p&gt;In my previous blog post, I talked about &lt;a href=&quot;http://www.tomdupont.net/2016/08/optimizing-dynamic-method-invokes-in-net.html&quot;&gt;Optimizing Dynamic Method Invokes in .NET&lt;/a&gt;. In this post, we will use that information to create a static helper method that is &lt;i&gt;twice as fast as MethodInfo.Invoke&lt;/i&gt;.

&lt;p&gt;Basically, we create and cache a delegate in a concurrent dictionary, and then cast both it and it&#39;s arguments to dynamics and invoke them directly. The concurrent dictionary introduces overhead, but it still more than twice as fast as calling MethodInfo.Invoke. Please note that this method is highly optimized to reduce the use of hash code look ups, property getters, closure allocations, and if checks.&lt;/p&gt;

&lt;p&gt;let&#39;s take a look at the code...&lt;/p&gt;

&lt;h3 style=&quot;margin-top:15px; margin-bottom:10px;&quot;&gt;InvokeHelpers.EfficientInvoke&lt;/h3&gt;

&lt;style&gt;#efficientinvoke &gt; pre { white-space: pre-wrap; }&lt;/style&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot; id=&quot;efficientinvoke&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; InvokeHelpers&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; TooManyArgsMessage = &lt;span class=&quot;str&quot;&gt;&quot;Invokes for more than 10 args are not yet implemented&quot;&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; Type VoidType = &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; ConcurrentDictionary&amp;lt;Tuple&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;&amp;gt;, DelegatePair&amp;gt; DelegateMap &lt;/pre&gt;
&lt;pre&gt;        = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ConcurrentDictionary&amp;lt;Tuple&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;&amp;gt;, DelegatePair&amp;gt;();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; EfficientInvoke(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; obj, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; methodName, &lt;span class=&quot;kwrd&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;[] args)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; key = Tuple.Create(methodName, obj);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; delPair = DelegateMap.GetOrAdd(key, CreateDelegate);&lt;/pre&gt;
&lt;pre&gt;            &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (delPair.HasReturnValue)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;switch&lt;/span&gt; (delPair.ArgumentCount)&lt;/pre&gt;
&lt;pre&gt;            {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 0: &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; delPair.Delegate();&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 1: &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; delPair.Delegate((dynamic)args[0]);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 2: &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; delPair.Delegate((dynamic)args[0], (dynamic)args[1]);&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 3: &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; delPair.Delegate((dynamic)args[0], (dynamic)args[1], (dynamic)args[2]);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 4: &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; delPair.Delegate((dynamic)args[0], (dynamic)args[1], (dynamic)args[2], (dynamic)args[3]);&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 5: &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; delPair.Delegate((dynamic)args[0], (dynamic)args[1], (dynamic)args[2], (dynamic)args[3], (dynamic)args[4]);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 6: &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; delPair.Delegate((dynamic)args[0], (dynamic)args[1], (dynamic)args[2], (dynamic)args[3], (dynamic)args[4], (dynamic)args[5]);&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 7: &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; delPair.Delegate((dynamic)args[0], (dynamic)args[1], (dynamic)args[2], (dynamic)args[3], (dynamic)args[4], (dynamic)args[5], (dynamic)args[6]);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 8: &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; delPair.Delegate((dynamic)args[0], (dynamic)args[1], (dynamic)args[2], (dynamic)args[3], (dynamic)args[4], (dynamic)args[5], (dynamic)args[6], (dynamic)args[7]);&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 9: &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; delPair.Delegate((dynamic)args[0], (dynamic)args[1], (dynamic)args[2], (dynamic)args[3], (dynamic)args[4], (dynamic)args[5], (dynamic)args[6], (dynamic)args[7], (dynamic)args[8]);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 10: &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; delPair.Delegate((dynamic)args[0], (dynamic)args[1], (dynamic)args[2], (dynamic)args[3], (dynamic)args[4], (dynamic)args[5], (dynamic)args[6], (dynamic)args[7], (dynamic)args[8], (dynamic)args[9]);&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;kwrd&quot;&gt;default&lt;/span&gt;: &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; NotImplementedException(TooManyArgsMessage);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            }&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;switch&lt;/span&gt; (delPair.ArgumentCount)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 0: delPair.Delegate(); &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 1: delPair.Delegate((dynamic)args[0]); &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 2: delPair.Delegate((dynamic)args[0], (dynamic)args[1]); &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 3: delPair.Delegate((dynamic)args[0], (dynamic)args[1], (dynamic)args[2]); &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 4: delPair.Delegate((dynamic)args[0], (dynamic)args[1], (dynamic)args[2], (dynamic)args[3]); &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 5: delPair.Delegate((dynamic)args[0], (dynamic)args[1], (dynamic)args[2], (dynamic)args[3], (dynamic)args[4]); &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 6: delPair.Delegate((dynamic)args[0], (dynamic)args[1], (dynamic)args[2], (dynamic)args[3], (dynamic)args[4], (dynamic)args[5]); &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 7: delPair.Delegate((dynamic)args[0], (dynamic)args[1], (dynamic)args[2], (dynamic)args[3], (dynamic)args[4], (dynamic)args[5], (dynamic)args[6]); &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 8: delPair.Delegate((dynamic)args[0], (dynamic)args[1], (dynamic)args[2], (dynamic)args[3], (dynamic)args[4], (dynamic)args[5], (dynamic)args[6], (dynamic)args[7]); &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 9: delPair.Delegate((dynamic)args[0], (dynamic)args[1], (dynamic)args[2], (dynamic)args[3], (dynamic)args[4], (dynamic)args[5], (dynamic)args[6], (dynamic)args[7], (dynamic)args[8]); &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; 10: delPair.Delegate((dynamic)args[0], (dynamic)args[1], (dynamic)args[2], (dynamic)args[3], (dynamic)args[4], (dynamic)args[5], (dynamic)args[6], (dynamic)args[7], (dynamic)args[8], (dynamic)args[9]); &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;default&lt;/span&gt;: &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; NotImplementedException(TooManyArgsMessage);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; DelegatePair CreateDelegate(Tuple&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;&amp;gt; key)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; method = key.Item2&lt;/pre&gt;
&lt;pre&gt;            .GetType()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            .GetMethod(key.Item1);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; argTypes = method&lt;/pre&gt;
&lt;pre&gt;            .GetParameters()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            .Select(p =&amp;gt; p.ParameterType)&lt;/pre&gt;
&lt;pre&gt;            .Concat(&lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt;[] { method.ReturnType })&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            .ToArray();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; newDelType = Expression.GetDelegateType(argTypes);&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; newDel = Delegate.CreateDelegate(newDelType, key.Item2, method);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; DelegatePair(newDel, argTypes.Length - 1, method.ReturnType != VoidType);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; DelegatePair&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; DelegatePair(dynamic del, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; argumentCount, &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; hasReturnValue)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            Delegate = del;&lt;/pre&gt;
&lt;pre&gt;            ArgumentCount = argumentCount;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            HasReturnValue = hasReturnValue;&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; dynamic Delegate;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; ArgumentCount;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; HasReturnValue;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Now let&#39;s take a look at some performance tests...&lt;/p&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;h3 style=&quot;margin-top:15px; margin-bottom:10px;&quot;&gt;Unit Tests&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; InvokeHelpersTests&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; Iterations = 1000000;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; TestClass Obj = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; TestClass();&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;[] Args = { 1, &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt; };&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; ITestOutputHelper _output;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; InvokeHelpersTests(ITestOutputHelper output)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        _output = output;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;rem&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;rem&quot;&gt;/// This is not realistic, because our million invokes do not simulate&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;rem&quot;&gt;/// the cost of looking up the MethodInfo. However, for the sake of&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;rem&quot;&gt;/// argument, this takes 930,136 ticks for one million iterations.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;rem&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    [Fact]&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; MethodInfoInvoke()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; methodInfo = Obj.GetType().GetMethod(&lt;span class=&quot;str&quot;&gt;&quot;TestMethod&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw0 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre&gt;        methodInfo.Invoke(Obj, Args);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        sw0.Stop();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw1 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; Iterations; i++)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            methodInfo.Invoke(Obj, Args);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;        sw1.Stop();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        _output.WriteLine(sw0.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _output.WriteLine(sw1.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;rem&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;rem&quot;&gt;/// This use case is more realistic, where we look up the MethodInfo&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;rem&quot;&gt;/// each iteration. This takes 1,370,052 ticks for one million iterations.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;rem&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    [Fact]&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; GetMethodInfoInvoke()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw0 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre&gt;        Obj.GetType().GetMethod(&lt;span class=&quot;str&quot;&gt;&quot;TestMethod&quot;&lt;/span&gt;).Invoke(Obj, Args);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        sw0.Stop();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw1 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; Iterations; i++)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            Obj.GetType().GetMethod(&lt;span class=&quot;str&quot;&gt;&quot;TestMethod&quot;&lt;/span&gt;).Invoke(Obj, Args);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;        sw1.Stop();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        _output.WriteLine(sw0.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _output.WriteLine(sw1.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;rem&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;rem&quot;&gt;/// This is an apples to apples comparision of using a ConcurrentDictionary to cache&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;rem&quot;&gt;/// the MethodInfo lookup. This takes 1,300,751 ticks for one million iterations.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;rem&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    [Fact]&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; MappedMethodInfoInvoke()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw0 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre&gt;        MappedMethodInvokeHelpers.EfficientInvoke(Obj, &lt;span class=&quot;str&quot;&gt;&quot;TestMethod&quot;&lt;/span&gt;, Args);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        sw0.Stop();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw1 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; Iterations; i++)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            MappedMethodInvokeHelpers.EfficientInvoke(Obj, &lt;span class=&quot;str&quot;&gt;&quot;TestMethod&quot;&lt;/span&gt;, Args);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;        sw1.Stop();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        _output.WriteLine(sw0.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _output.WriteLine(sw1.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;rem&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;rem&quot;&gt;/// Here is our custom optimized solution, which beats ALL of the previous iterations by&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;rem&quot;&gt;/// more than a factor of 2! This only takes 467,158 ticks for one million iterations.&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;rem&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;    [Fact]&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; EfficientInvoke()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw0 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre&gt;        InvokeHelpers.EfficientInvoke(Obj, &lt;span class=&quot;str&quot;&gt;&quot;TestMethod&quot;&lt;/span&gt;, Args);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        sw0.Stop();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw1 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; Iterations; i++)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            InvokeHelpers.EfficientInvoke(Obj, &lt;span class=&quot;str&quot;&gt;&quot;TestMethod&quot;&lt;/span&gt;, Args);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;        sw1.Stop();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        _output.WriteLine(sw0.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _output.WriteLine(sw1.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; TestClass&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; TestMethod(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; i, &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; b)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; i + (b ? 1 : 2);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; MappedMethodInvokeHelpers&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; ConcurrentDictionary&amp;lt;Tuple&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;&amp;gt;, MethodInfo&amp;gt; DelegateMap&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ConcurrentDictionary&amp;lt;Tuple&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;&amp;gt;, MethodInfo&amp;gt;();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; EfficientInvoke(&lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; obj, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; methodName, &lt;span class=&quot;kwrd&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;[] args)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; key = Tuple.Create(methodName, obj);&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; methodInfo = DelegateMap.GetOrAdd(key, GetMethodInfo);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; methodInfo.Invoke(obj, args);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; MethodInfo GetMethodInfo(Tuple&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;&amp;gt; key)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; key.Item2.GetType().GetMethod(key.Item1);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/6112842309461345254/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/08/dynamically-invoke-methods-quickly-with.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/6112842309461345254'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/6112842309461345254'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/08/dynamically-invoke-methods-quickly-with.html' title='Dynamically Invoke Methods Quickly, with InvokeHelpers.EfficientInvoke'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-7339631774355832645</id><published>2016-08-21T12:05:00.002-07:00</published><updated>2016-08-21T12:15:10.120-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="Delegate"/><category scheme="http://www.blogger.com/atom/ns#" term="Dynamic"/><category scheme="http://www.blogger.com/atom/ns#" term="Invoke"/><category scheme="http://www.blogger.com/atom/ns#" term="Performance"/><category scheme="http://www.blogger.com/atom/ns#" term="Reflection"/><title type='text'>Optimizing Dynamic Method Invokes in .NET</title><content type='html'>&lt;p&gt;I recently had a lot of fun helping to optimize some RPC code that was using reflection to dynamically invoke methods in a C# application. Below are a list of implementations that we experimented with, and their performance.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Directly Invoking the Method&lt;/li&gt;
&lt;li&gt;Using MethodInfo.Invoke&lt;/li&gt;
&lt;li&gt;Using Delegate.DynamicInvoke&lt;/li&gt;
&lt;li&gt;Casting to a Func&lt;/li&gt;
&lt;li&gt;Casting a Delegate to Dynamic&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;b&gt;Spoilers:&lt;/b&gt; Here are the results. (The tests for this can be see below.)&lt;/p&gt;

&lt;table border=&quot;1&quot; cellpadding=&quot;5&quot; style=&quot;margin: auto; border-spacing: 0px; text-align: center; width: 600px;&quot;&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;First Call (Ticks)&lt;/th&gt;
&lt;th&gt;Next Million Calls&lt;/th&gt;
&lt;th&gt;Invoke Comparison&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Invoke&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;39795&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MethodInfo.Invoke&lt;/td&gt;
&lt;td&gt;12&lt;/td&gt;
&lt;td&gt;967523&lt;/td&gt;
&lt;td&gt;x24&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Delegate.DynamicInvoke&lt;/td&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;1580086&lt;/td&gt;
&lt;td&gt;x39&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Func Invoke&lt;/td&gt;
&lt;td&gt;731&lt;/td&gt;
&lt;td&gt;41331&lt;/td&gt;
&lt;td&gt;x1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dynamic Cast&lt;/td&gt;
&lt;td&gt;1126896&lt;/td&gt;
&lt;td&gt;85495&lt;/td&gt;
&lt;td&gt;x2&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;

&lt;p&gt;&lt;b&gt;Conclusion:&lt;/b&gt; Invoking a method or delegate directly is always fastest, but when you need to execute code dynamically, then (after the first invoke) the dynamic invoke of a delegate is significantly faster than using reflection.&lt;/p&gt;

&lt;p style=&quot;text-align:center&quot;&gt;&lt;img src=&quot;https://sites.google.com/site/tdupont750/MethodInvokePerformance.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let&#39;s take a look at the test code...&lt;/p&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;h3 style=&quot;margin-top:15px; margin-bottom:10px;&quot;&gt;Unit Tests&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; InvokePerformance&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; Iterations = 1000000;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;[] Args = {1, &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;};&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; TestClass Obj = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; TestClass();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; Type Type = &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(TestClass);&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; MethodInfo Method = Type.GetMethod(&lt;span class=&quot;str&quot;&gt;&quot;TestMethod&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; ITestOutputHelper _output;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; InvokePerformance(ITestOutputHelper output)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        _output = output;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    [Fact]&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Invoke()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; arg0 = (&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;) Args[0];&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; arg1 = (&lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt;) Args[1];&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw0 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre&gt;        Method.Invoke(Obj, Args);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        sw0.Stop();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw1 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; Iterations; i++)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            Obj.TestMethod(arg0, arg1);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;        sw1.Stop();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        _output.WriteLine(sw0.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _output.WriteLine(sw1.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    [Fact]&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; MethodInfoInvoke()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw0 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre&gt;        Method.Invoke(Obj, Args);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        sw0.Stop();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw1 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; Iterations; i++)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            Method.Invoke(Obj, Args);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;        sw1.Stop();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        _output.WriteLine(sw0.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _output.WriteLine(sw1.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    [Fact]&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; DelegateDynamicInvoke()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; delType = Expression.GetDelegateType(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;), &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt;), &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;));&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; del = Delegate.CreateDelegate(delType, Obj, Method);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw0 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        del.DynamicInvoke(Args);&lt;/pre&gt;
&lt;pre&gt;        sw0.Stop();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw1 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; Iterations; i++)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            del.DynamicInvoke(Args);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        sw1.Stop();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _output.WriteLine(sw0.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre&gt;        _output.WriteLine(sw1.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    [Fact]&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; FuncInvoke()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; delType = Expression.GetDelegateType(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;), &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt;), &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;));&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; del = (Func&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;&amp;gt;) Delegate.CreateDelegate(delType, Obj, Method);&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; arg0 = (&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;) Args[0];&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; arg1 = (&lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt;) Args[1];&lt;/pre&gt;
&lt;pre&gt;            &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw0 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre&gt;        del(arg0, arg1);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        sw0.Stop();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw1 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; Iterations; i++)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            del(arg0, arg1);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;        sw1.Stop();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        _output.WriteLine(sw0.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _output.WriteLine(sw1.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;/pre&gt;
&lt;pre&gt;    [Fact]&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; DynamicCast()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; delType = Expression.GetDelegateType(&lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;), &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt;), &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt;));&lt;/pre&gt;
&lt;pre&gt;        dynamic del = Delegate.CreateDelegate(delType, Obj, Method);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        dynamic arg0 = Args[0];&lt;/pre&gt;
&lt;pre&gt;        dynamic arg1 = Args[1];&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw0 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        del(arg0, arg1);&lt;/pre&gt;
&lt;pre&gt;        sw0.Stop();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; sw1 = Stopwatch.StartNew();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt; (&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; Iterations; i++)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            del(arg0, arg1);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        sw1.Stop();&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _output.WriteLine(sw0.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre&gt;        _output.WriteLine(sw1.ElapsedTicks.ToString());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; TestClass&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; TestMethod(&lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; i, &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; b)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; i + (b ? 1 : 2);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/7339631774355832645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/08/optimizing-dynamic-method-invokes-in-net.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/7339631774355832645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/7339631774355832645'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/08/optimizing-dynamic-method-invokes-in-net.html' title='Optimizing Dynamic Method Invokes in .NET'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-1268091863245552775</id><published>2016-07-31T12:00:00.000-07:00</published><updated>2016-08-02T23:40:06.753-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term=".NET Core"/><category scheme="http://www.blogger.com/atom/ns#" term=".NET Standard"/><category scheme="http://www.blogger.com/atom/ns#" term="NuGet"/><category scheme="http://www.blogger.com/atom/ns#" term="Octopus"/><title type='text'>Can I port my application to .NET Core?</title><content type='html'>&lt;p&gt;I am very excited about .NET Core, and I am looking forward to porting my projects to it. Generally porting your own code is a straight forward task, but updating all of your dependencies can be quite daunting. Good news: the guys over at Octopus have built an awesome little site that helps you determine the state of your dependencies!&lt;/p&gt;

&lt;h3 style=&quot;text-align:center;&quot;&gt;&lt;a href=&quot;https://icanhasdot.net/&quot; target=&quot;_blank&quot;&gt;I Can Has .NET Core&lt;/a&gt;&lt;/h3&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;&lt;img src=&quot;https://sites.google.com/site/tdupont750/icanhasdotnet.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/1268091863245552775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/07/can-i-port-my-application-to-net-core.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/1268091863245552775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/1268091863245552775'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/07/can-i-port-my-application-to-net-core.html' title='Can I port my application to .NET Core?'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-5959874005262477410</id><published>2016-07-24T12:34:00.000-07:00</published><updated>2016-07-24T12:34:41.582-07:00</updated><title type='text'>Make your NuGet Server use NLog</title><content type='html'>&lt;img style=&quot;float:right; width:120px; margin-left:20px;&quot; src=&quot;https://sites.google.com/site/tdupont750/nuget.png&quot;&gt;

&lt;p&gt;The latest version of &lt;a href=&quot;https://www.nuget.org/packages/NuGet.Server/&quot; target=&quot;_blank&quot;&gt;NuGet.Server&lt;/a&gt; is fast, stable, and super simple to setup. As for most .NET tools, &lt;a href=&quot;http://www.hanselman.com/blog/HowToHostYourOwnNuGetServerAndPackageFeed.aspx&quot; target=&quot;_blank&quot;&gt;Scott Hanselman&lt;/a&gt; already create a great write up about how to use it.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;However, I was very disappointed at how unintuitive it was to get wire up a custom logger!&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;You need to take several steps to make the official NuGet server write to something like NLog:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create a log wrapper.&lt;/li&gt;
&lt;li&gt;Implement NuGet.Server.Logging.ILogger.&lt;/li&gt;
&lt;li&gt;Implement NuGet.ILogger...&lt;/li&gt;
&lt;li&gt;...which also makes you implement NuGet.IFileConflictResolver!&lt;/li&gt;
&lt;li&gt;Implement your own NuGet.Server.IServiceResolver&lt;/li&gt;
&lt;li&gt;When instantiating ServerPackageRepository...&lt;/li&gt;
&lt;li&gt;...pass in the ILogger...&lt;/li&gt;
&lt;li&gt;...AND set the Logger property!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Still confused? &lt;a href=&quot;https://github.com/tdupont750/NuGet.Server.NLog&quot; target=&quot;_blank&quot;&gt;Pull the code here&lt;/a&gt;, or take a look below!&lt;/p&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;NLogLogger&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; NLogLogger : Logging.ILogger, ILogger&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; global::NLog.ILogger _logger;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; NLogLogger(global::NLog.ILogger logger)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _logger = logger;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Log(LogLevel level, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; message, &lt;span class=&quot;kwrd&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;[] args)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;switch&lt;/span&gt; (level)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; LogLevel.Verbose:&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                _logger.Trace(message, args);&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; LogLevel.Info:&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                _logger.Info(message, args);&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; LogLevel.Warning:&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                _logger.Warn(message, args);&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; LogLevel.Error:&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                _logger.Error(message, args);&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;default&lt;/span&gt;:&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ArgumentOutOfRangeException(nameof(level), level, &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; FileConflictResolution ResolveFileConflict(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; message)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _logger.Warn(message);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// This is what the default NullLogger returns.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; FileConflictResolution.Ignore;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; Log(MessageLevel level, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; message, &lt;span class=&quot;kwrd&quot;&gt;params&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt;[] args)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;switch&lt;/span&gt; (level)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; MessageLevel.Info:&lt;/pre&gt;
&lt;pre&gt;                _logger.Info(message, args);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; MessageLevel.Warning:&lt;/pre&gt;
&lt;pre&gt;                _logger.Warn(message, args);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; MessageLevel.Debug:&lt;/pre&gt;
&lt;pre&gt;                _logger.Debug(message, args);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; MessageLevel.Error:&lt;/pre&gt;
&lt;pre&gt;                _logger.Error(message, args);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;break&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;default&lt;/span&gt;:&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ArgumentOutOfRangeException(nameof(level), level, &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;NLogServiceResolver&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; NLogServiceResolver : IServiceResolver&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; IHashProvider _hashProvider;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; IServerPackageRepository _packageRepository;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; IPackageAuthenticationService _packageAuthenticationService;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; IPackageService _packageService;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; ILogger _logger;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; Logging.ILogger _loggingLogger;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; NLogServiceResolver()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; logger = LogManager.GetCurrentClassLogger();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        logger.Info(&lt;span class=&quot;str&quot;&gt;&quot;Initializing NLogServiceResolver&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; nlogLogger = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; NLogLogger(logger);&lt;/pre&gt;
&lt;pre&gt;        _logger = nlogLogger;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _loggingLogger = nlogLogger;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _hashProvider = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; CryptoHashProvider(&lt;span class=&quot;str&quot;&gt;&quot;SHA512&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;        _packageRepository = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ServerPackageRepository(&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            PackageUtility.PackagePhysicalPath,&lt;/pre&gt;
&lt;pre&gt;            _hashProvider,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            _loggingLogger)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;rem&quot;&gt;// The base class has a separate logger that you have to set.&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;            Logger = _logger&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        };&lt;/pre&gt;
&lt;pre&gt;            &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        _packageAuthenticationService = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; PackageAuthenticationService();&lt;/pre&gt;
&lt;pre&gt;        _packageService = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; PackageService(_packageRepository, _packageAuthenticationService);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; Resolve(Type type)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (type == &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(IHashProvider))&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; _hashProvider;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (type == &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(IServerPackageRepository))&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; _packageRepository;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (type == &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(IPackageAuthenticationService))&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; _packageAuthenticationService;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (type == &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(IPackageService))&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; _packageService;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (type == &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(ILogger))&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; _logger;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (type == &lt;span class=&quot;kwrd&quot;&gt;typeof&lt;/span&gt;(Logging.ILogger))&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; _loggingLogger;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;

</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/5959874005262477410/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/07/make-your-nuget-server-use-nlog.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/5959874005262477410'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/5959874005262477410'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/07/make-your-nuget-server-use-nlog.html' title='Make your NuGet Server use NLog'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-1833572581953716728</id><published>2016-07-17T22:02:00.001-07:00</published><updated>2016-07-17T22:02:50.663-07:00</updated><title type='text'>Should you open source your software?</title><content type='html'>&lt;p style=&quot;text-align:center;&quot;&gt;&lt;img src=&quot;http://static1.squarespace.com/static/5681f92f69492e9cac51bb8b/t/577db62dbebafbf9bab92d3c/1467856445474/?format=500w&quot;&gt;&lt;/p&gt;

&lt;p&gt;Every Tuesday I help host the &lt;a href=&quot;http://www.qq-cast.com/&quot; target=&quot;_blank&quot;&gt;QQ Cast&lt;/a&gt;, where we fabricate answers to geek culture&#39;s most superfluous questions. For our 50th Quest, my good friend &lt;a href=&quot;http://www.robokindrobots.com/robots4autism-home/our-team/&quot; target=&quot;_blank&quot;&gt;Matt Stevenson&lt;/a&gt; joined us to talk about open source software.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;&lt;b&gt;&lt;a href=&quot;http://www.qq-cast.com/podcast/2016/7/6/quest-50-should-you-open-source-your-software&quot; target=&quot;_blank&quot;&gt;QQ Cast - Quest 50 - Should you open source your software?&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;00:00 - Mic Check and Introductions&lt;/li&gt;
&lt;li&gt;05:30 - Is &quot;Expand Enhance Extinguish&quot; still alive and well?&lt;/li&gt;
&lt;li&gt;19:40 - Can we build a sustainable infrastructure without open source software?&lt;/li&gt;
&lt;li&gt;33:00 - How much structure do we like to see in our frameworks?&lt;/li&gt;
&lt;li&gt;40:50 - What are some great open source projects?&lt;/li&gt;
&lt;li&gt;47:15 - Was heartbleed a good thing or a bad thing?&lt;/li&gt;
&lt;li&gt;54:30 - Does contributing to open source projects help your resume?&lt;/li&gt;
&lt;li&gt;60:00 - Should you open source your software?&lt;/li&gt;
&lt;li&gt;70:00 - Wrap up!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please always remember that all views and opinions expressed on the podcast are representative solely of the person expressing them; not of their friends and family, not of their coworkers, and certainly not of their employers, past, present, or future.&lt;/p&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/1833572581953716728/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/07/should-you-open-source-your-software.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/1833572581953716728'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/1833572581953716728'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/07/should-you-open-source-your-software.html' title='Should you open source your software?'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-29451797241851352</id><published>2016-06-30T11:26:00.000-07:00</published><updated>2016-07-02T11:27:33.594-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term=".NET"/><category scheme="http://www.blogger.com/atom/ns#" term="C#"/><category scheme="http://www.blogger.com/atom/ns#" term="CSharp"/><category scheme="http://www.blogger.com/atom/ns#" term="Default Parameter"/><title type='text'>Updating Default Parameters in .NET Assemblies</title><content type='html'>&lt;img style=&quot;float:right; width:225px; margin-left:20px; margin-bottom:20px;&quot; src=&quot;https://sites.google.com/site/tdupont750/DefaultParameters.jpg&quot; /&gt;

&lt;p&gt;One of the things that I love about C# is how so many of it&#39;s features are just very conveniently designed compiler tricks. This means that, just like any other magic trick, once you know how the trick is performed you immediately realize that there really is nothing magical about it.&lt;/p&gt;

&lt;p&gt;So, let&#39;s talk about default parameters. They are actually just constant values that get compiled into your code when you go to use a method that has them. Let&#39;s look at an example...&lt;/p&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;The Code&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;enum&lt;/span&gt; Country&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    US,&lt;/pre&gt;
&lt;pre&gt;    CA&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; SharedUtility&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; CanDrink(&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; age, &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Country country = Country.CA)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;switch&lt;/span&gt; (country)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; Country.US:&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; age &amp;gt;= 21;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; Country.CA:&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; age &amp;gt;= 18;&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;default&lt;/span&gt;:&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ArgumentException(&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                    &lt;span class=&quot;str&quot;&gt;&quot;Invalid Country&quot;&lt;/span&gt;,&lt;/pre&gt;
&lt;pre&gt;                    nameof(country));&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; SharedUtilityTests&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    [Fact]&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; CanDrink()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; result = SharedUtility.CanDrink(20);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// The line above will compile into the following:&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// var result = SharedUtility.CanDrink(20, Country.CA);&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// Thus, the Assert below will succeed!&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;        Assert.True(result, &lt;span class=&quot;str&quot;&gt;&quot;The default was not US!&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;So, now that you know how the trick is performed, how could this cause a problem for you? Specifically, what happens if you update a library that exposes methods with default parameters?&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Nothing will change, until you recompile against the library!&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;If another library changes their default parameters, but you do not recompile your code against it, then your code will be using the old default values! Let&#39;s look back at the previous example and see why this could cause confusion...&lt;/p&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;The Change&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;enum&lt;/span&gt; Country&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    US,&lt;/pre&gt;
&lt;pre&gt;    CA&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; SharedUtility&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;bool&lt;/span&gt; CanDrink(&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; age, &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// NOTE: We have changed the default value!&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        Country country = Country.US)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;switch&lt;/span&gt; (country)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; Country.US:&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; age &amp;gt;= 21;&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;case&lt;/span&gt; Country.CA:&lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; age &amp;gt;= 18;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;default&lt;/span&gt;:&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;kwrd&quot;&gt;throw&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; ArgumentException(&lt;/pre&gt;
&lt;pre&gt;                    &lt;span class=&quot;str&quot;&gt;&quot;Invalid Country&quot;&lt;/span&gt;,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                    nameof(country));&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;}&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; SharedUtilityTests&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;{&lt;/pre&gt;
&lt;pre&gt;    [Fact]&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; CanDrink()&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; result = SharedUtility.CanDrink(20);&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// If you do NOT recompile and just replace the DLL,&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;// then this test will still pass. However, as soon&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;rem&quot;&gt;// as you recompile this test will start failing!&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        Assert.True(result, &lt;span class=&quot;str&quot;&gt;&quot;The default was not US!&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Don&#39;t take my word for it, here are screenshots of that code in action...&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;
&lt;img src=&quot;https://sites.google.com/site/tdupont750/DefaultParams.png&quot; /&gt;
&lt;/p&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/29451797241851352/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/06/updating-default-parameters-in-net.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/29451797241851352'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/29451797241851352'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/06/updating-default-parameters-in-net.html' title='Updating Default Parameters in .NET Assemblies'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-3764725969456209714</id><published>2016-06-26T18:57:00.000-07:00</published><updated>2016-06-26T19:27:20.953-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Chrome"/><category scheme="http://www.blogger.com/atom/ns#" term="Chromecast"/><category scheme="http://www.blogger.com/atom/ns#" term="HTML5"/><category scheme="http://www.blogger.com/atom/ns#" term="MP3"/><category scheme="http://www.blogger.com/atom/ns#" term="Playlist"/><category scheme="http://www.blogger.com/atom/ns#" term="SASS"/><category scheme="http://www.blogger.com/atom/ns#" term="TypeScript"/><category scheme="http://www.blogger.com/atom/ns#" term="VSCode"/><title type='text'>MP3 Playlist for Chromecast</title><content type='html'>&lt;p&gt;Come to find out, I am a very retro guy when it comes to music. I have these old things that I like to use to play music, you may not have heard of them, they are called MP3s. They are kind of like 8-track tapes, but digital, not in the cloud, and not old enough to be cool yet.&lt;/p&gt;

&lt;h3&gt;How do you play MP3s via Chromecast?&lt;/h3&gt;

&lt;p&gt;The &lt;a href=&quot;https://support.google.com/chromecast/answer/6279417?hl=en&quot; target=&quot;_blank&quot;&gt;official answer&lt;/a&gt; is to use Google Play, but that implies that you want to both pay for that service and upload your files to the cloud. The &lt;a href=&quot;http://www.groovypost.com/howto/play-local-media-files-google-chromecast/&quot; target=&quot;_blank&quot;&gt;unofficial answer&lt;/a&gt; is to drag and drop your MP3s into a Chrome tab and cast that tab, however this does not allow you to create a playlist.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;&lt;img src=&quot;https://sites.google.com/site/tdupont750/ChromecastAndMP3s.png&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Introducing Playlist for Chromecast&lt;/h2&gt;

&lt;p&gt;I have created a simple single page HTML 5 application that will act as a playlist for MP3s on your computer. Just &lt;a href=&quot;https://github.com/tdupont750/PlaylistForChromecast/archive/master.zip&quot; target=&quot;_blank&quot;&gt;download the project&lt;/a&gt; and open up release/playlist.html in Chrome, then drag and drop MP3s on to the page.&lt;/p&gt;

&lt;p style=&quot;text-align:center;&quot;&gt;&lt;img src=&quot;https://sites.google.com/site/tdupont750/Playlist.PNG&quot;&gt;&lt;/p&gt;

&lt;h3&gt;Development&lt;/h3&gt;

&lt;p&gt;I had a lot of fun making this, and I&#39;m not done. I intend to use this project as a case study to talk about VSCode, TypeScript, SASS, HTML5 Audio, NPM, and unit testing. For now, I just wanted to start by getting this initial post up, but expect more to follow.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/tdupont750/PlaylistForChromecast&quot; target=&quot;_blank&quot;&gt;Source on GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;What&#39;s next?&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Update project documentation.&lt;/li&gt;
&lt;li&gt;Create unit tests.&lt;/li&gt;
&lt;li&gt;Add theme support.&lt;/li&gt;
&lt;li&gt;Write blog posts about development.&lt;/li&gt;
&lt;li&gt;Maybe host it on a domain.&lt;/li&gt;
&lt;li&gt;Maybe submit it as a Chrome application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/3764725969456209714/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/06/mp3-playlist-for-chromecast.html#comment-form' title='40 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/3764725969456209714'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/3764725969456209714'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/06/mp3-playlist-for-chromecast.html' title='MP3 Playlist for Chromecast'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>40</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-3569850215721462684</id><published>2016-06-18T11:07:00.000-07:00</published><updated>2016-06-26T09:22:42.912-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="Ajax"/><category scheme="http://www.blogger.com/atom/ns#" term="ajaxPrefilter"/><category scheme="http://www.blogger.com/atom/ns#" term="Cache"/><category scheme="http://www.blogger.com/atom/ns#" term="Caching"/><category scheme="http://www.blogger.com/atom/ns#" term="jQuery"/><title type='text'>Client Side Caching for jQuery</title><content type='html'>&lt;img style=&quot;float: right; width: 150px; margin-left: 20px;&quot; src=&quot;https://sites.google.com/site/tdupont750/jquery-icon.png&quot; /&gt;

&lt;p&gt;&lt;b&gt;Updates: &lt;i&gt;6/26/16&lt;/i&gt;&lt;/b&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fixed bug where triple equals null check would miss.&lt;/li&gt;
&lt;li&gt;Added support for data driven cache key.&lt;/li&gt;
&lt;li&gt;Removed let and const statements (some minifiers were having a hard time with them)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b&gt;Original:&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;There is great question on Stack Overflow about &lt;a href=&quot;http://stackoverflow.com/questions/17104265/caching-a-jquery-ajax-response-in-javascript-browser&quot; target=&quot;_blank&quot;&gt;caching a jquery ajax response in javascript/browser&lt;/a&gt;. Unfortunately, even thought it was a good solution, it did not do quite what I needed it to.&lt;/p&gt;

&lt;p&gt;The application I was trying to optimize sometimes made redundant parallel requests, and I needed my caching solution to include a queuing system to prevent duplicate fetches.&lt;/p&gt;

&lt;p&gt;Below is a simple solution that uses &lt;a href=&quot;https://api.jquery.com/jQuery.ajaxPrefilter/&quot; target=&quot;_blank&quot;&gt;jQuery.ajaxPrefilter&lt;/a&gt; to check a local cache prior to making GET requests. Additionally, it will queue the callback if the request is already in flight. The cache stores the queue in both memory and local storage, ensuring that the cache will persist across page loads.&lt;/p&gt;

&lt;h3 style=&quot;margin-top: 20px; margin-bottom: 15px;&quot;&gt;Implementation&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;(function ($) {&lt;/pre&gt;
&lt;pre&gt;  &lt;span class=&quot;str&quot;&gt;&quot;use strict&quot;&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;  &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; timeout = 60000;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; cache = {};&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  $.ajaxPrefilter(onPrefilter);&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  function onPrefilter(options, originalOptions) {&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (options.cache !== &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;) {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;      &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; callback = originalOptions.complete || $.noop;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; cacheKey = getCacheKey(originalOptions);&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    options.cache = &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;    options.beforeSend = onBeforeSend;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    options.complete = onComplete;&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    function onBeforeSend() {&lt;/pre&gt;
&lt;pre&gt;      &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; cachedItem = tryGet(cacheKey);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;      &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!!cachedItem) {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (cachedItem.data === &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;) {&lt;/pre&gt;
&lt;pre&gt;          cachedItem.queue.push(callback);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        } &lt;span class=&quot;kwrd&quot;&gt;else&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;          setTimeout(onCacheHit, 0);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;false&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;      }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;      cachedItem = createCachedItem();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;      cachedItem.queue.push(callback);&lt;/pre&gt;
&lt;pre&gt;      setCache(cacheKey, cachedItem);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;      &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;      function onCacheHit() {&lt;/pre&gt;
&lt;pre&gt;        invoke(callback, cachedItem);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;      }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;    function onComplete(data, textStatus) {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;      &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; cachedItem = tryGet(cacheKey);&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;      &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!!cachedItem) {&lt;/pre&gt;
&lt;pre&gt;        cachedItem.data = data;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        cachedItem.status = textStatus;&lt;/pre&gt;
&lt;pre&gt;        setCache(cacheKey, cachedItem);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; queuedCallback;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        while (!!(queuedCallback = cachedItem.queue.pop())) {&lt;/pre&gt;
&lt;pre&gt;          invoke(queuedCallback, cachedItem);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;      }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;      cachedItem = createCachedItem(data, textStatus);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;      setCache(cacheKey, cachedItem);&lt;/pre&gt;
&lt;pre&gt;      invoke(callback, cachedItem);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt;  }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;  function tryGet(cacheKey) {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; cachedItem = cache[cacheKey];&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!!cachedItem) {&lt;/pre&gt;
&lt;pre&gt;      &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; diff = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Date().getTime() - cachedItem.created;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;      &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (diff &amp;lt; timeout) {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; cachedItem;&lt;/pre&gt;
&lt;pre&gt;      }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; item = localStorage.getItem(cacheKey);&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!!item) {&lt;/pre&gt;
&lt;pre&gt;      cachedItem = JSON.parse(item);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;      &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; diff = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Date().getTime() - cachedItem.created;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;      &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (diff &amp;lt; timeout) {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; cachedItem;&lt;/pre&gt;
&lt;pre&gt;      }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;      localStorage.removeItem(cacheKey);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    }&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;  }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;  function setCache(cacheKey, cachedItem) {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    cache[cacheKey] = cachedItem;&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; clone = createCachedItem(cachedItem.data, cachedItem.status, cachedItem.created);&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; json = JSON.stringify(clone);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    localStorage.setItem(cacheKey, json);&lt;/pre&gt;
&lt;pre&gt;  }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt; &lt;/pre&gt;
&lt;pre&gt;  function createCachedItem(data, status, created) {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; {&lt;/pre&gt;
&lt;pre&gt;      data: data || &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;      status: status,&lt;/pre&gt;
&lt;pre&gt;      created: created || &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Date().getTime(),&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;      queue: []&lt;/pre&gt;
&lt;pre&gt;    };&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  }&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  function invoke(callback, cachedItem) {&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; ($.isFunction(callback)) {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;      callback(cachedItem.data, cachedItem.status);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  }&lt;/pre&gt;
&lt;pre&gt;  &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  function getCacheKey(originalOptions) {&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!!originalOptions.data) {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;      &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; originalOptions.url + &lt;span class=&quot;str&quot;&gt;&quot;?&quot;&lt;/span&gt; + JSON.stringify(originalOptions.data);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; originalOptions.url;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;  }&lt;/pre&gt;
&lt;pre&gt; &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;})(jQuery);&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/3569850215721462684/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/06/client-side-caching-for-jquery.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/3569850215721462684'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/3569850215721462684'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/06/client-side-caching-for-jquery.html' title='Client Side Caching for jQuery'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-7670867138379929830</id><published>2016-05-27T07:11:00.000-07:00</published><updated>2016-05-27T07:11:04.269-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="B"/><category scheme="http://www.blogger.com/atom/ns#" term="Regex"/><category scheme="http://www.blogger.com/atom/ns#" term="Regular Expression"/><category scheme="http://www.blogger.com/atom/ns#" term="Replace Word"/><category scheme="http://www.blogger.com/atom/ns#" term="Word Boundaries"/><title type='text'>Word Boundaries Regex</title><content type='html'>&lt;div style=&quot;float:right; font-size:5em; margin:20px; margin-top:0px; font-weight:bold;&quot;&gt;\b&lt;/div&gt;

&lt;p&gt;This is the second time this week where I have had to ask myself &quot;how did I not know about this?&quot;&lt;/p&gt;

&lt;p&gt;There is a regex character to identify &lt;a href=&quot;http://www.regular-expressions.info/wordboundaries.html&quot; target=&quot;_blank&quot;&gt;word boundaries: &lt;b&gt;\b&lt;/b&gt;&lt;/a&gt; This is a zero length match, similar to the caret and dollar sign. It finds the boundaries between words, allowing you to search for a whole word match.&lt;/p&gt;

&lt;p&gt;Below is a sample extension method that uses this to replace words in a string.&lt;/p&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;Implementation&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; StringExtensions&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; Regex WordRegex = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Regex(&lt;span class=&quot;str&quot;&gt;@&quot;\b\w+\b&quot;&lt;/span&gt;, RegexOptions.Compiled);&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; ReplaceWords(&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; input,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; find,&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; replace,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        StringComparison comparison = StringComparison.InvariantCulture)&lt;/pre&gt;
&lt;pre&gt;    {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; WordRegex.Replace(input, m =&amp;gt; m.Value.Equals(find, comparison)&lt;/pre&gt;
&lt;pre&gt;            ? replace&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            : m.Value);&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;Unit Test&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; StringExtensionsTests&lt;/pre&gt;
&lt;pre&gt;{&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    [Fact]&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; ReplaceWords()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        Assert.Equal(&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;str&quot;&gt;&quot;This island can has beautiful&quot;&lt;/span&gt;,&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;str&quot;&gt;&quot;This island is beautiful&quot;&lt;/span&gt;.ReplaceWords(&lt;span class=&quot;str&quot;&gt;&quot;is&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;can has&quot;&lt;/span&gt;));&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        Assert.Equal(&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;str&quot;&gt;&quot;This island are beautiful&quot;&lt;/span&gt;,&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;str&quot;&gt;&quot;This island is beautiful&quot;&lt;/span&gt;.ReplaceWords(&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                &lt;span class=&quot;str&quot;&gt;&quot;IS&quot;&lt;/span&gt;, &lt;/pre&gt;
&lt;pre&gt;                &lt;span class=&quot;str&quot;&gt;&quot;are&quot;&lt;/span&gt;, &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                StringComparison.InvariantCultureIgnoreCase));&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/7670867138379929830/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/05/word-boundaries-regex.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/7670867138379929830'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/7670867138379929830'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/05/word-boundaries-regex.html' title='Word Boundaries Regex'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4063545436138319205.post-9035201734653449117</id><published>2016-05-22T11:26:00.000-07:00</published><updated>2016-05-22T11:58:48.637-07:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="C#"/><category scheme="http://www.blogger.com/atom/ns#" term="Caller Information"/><category scheme="http://www.blogger.com/atom/ns#" term="CallerMemberNameAttribute"/><category scheme="http://www.blogger.com/atom/ns#" term="Callsite"/><category scheme="http://www.blogger.com/atom/ns#" term="Common Logging"/><category scheme="http://www.blogger.com/atom/ns#" term="CSharp"/><category scheme="http://www.blogger.com/atom/ns#" term="NLog"/><category scheme="http://www.blogger.com/atom/ns#" term="Stack Frame"/><title type='text'>Common Logging Extensions with Caller Information</title><content type='html'>&lt;img src=&quot;http://devstickers.com/assets/img/pro/2p4i.png&quot; style=&quot;float:right; width: 200px; margin-left: 20px; margin-bottom: 20px;&quot; /&gt;

&lt;p&gt;&lt;i&gt;Update: Added the BreakParameter.&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;I have made it an (arguably bad) habit of manually adding the class and method name as a prefix to all my log lines. It is not that I enjoy typing out the same strings over and over, it&#39;s that I do not always trust things like the &lt;a href=&quot;https://github.com/NLog/NLog/wiki/Callsite-layout-renderer&quot; target=&quot;_blank&quot;&gt;NLog callsite&lt;/a&gt;. Using the stack frame to identify a calling method always requires a bit of cleverness on the part of the author, as you never can be totally sure when you are dealing with a wrapper class or an async call stack.&lt;/p&gt;

&lt;p&gt;I was recently introduced to the &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/mt653988.aspx&quot; target=&quot;_blank&quot;&gt;Caller Information attributes in C# 5&lt;/a&gt;, and now I think I am in love.&lt;/p&gt;

&lt;p&gt;Disclaimer: I have not used this very much yet, but I intend to start! I think that these attributes are absolutely brilliant in their simplicity: a compiler trick to insert debug information directly into your code. That is freak&#39;n sweet, and &lt;a href=&quot;http://geekswithblogs.net/BlackRabbitCoder/archive/2013/07/25/c.net-little-wonders-getting-caller-information.aspx&quot; target=&quot;_blank&quot;&gt;it&#39;s performant&lt;/a&gt;! I am not sure how this flew under my radar, but now that I know about it....&lt;/p&gt;

&lt;p&gt;Below is a little T4 template that I wrote up to generate overloads for Common Logging that will include caller information. To customize this for your needs, just update the the GetFormat method at the bottom of the template.&lt;/p&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;Unit Tests&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;   1:  &lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;   2:  &lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; System.Collections.Generic;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;   3:  &lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; Common.Logging.Simple;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;   4:  &lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; Xunit;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;   5:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;   6:  &lt;/span&gt;&lt;span class=&quot;kwrd&quot;&gt;namespace&lt;/span&gt; Common.Logging.Tests&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;   7:  &lt;/span&gt;{&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;   8:  &lt;/span&gt;    &lt;span class=&quot;rem&quot;&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;   9:  &lt;/span&gt;    &lt;span class=&quot;rem&quot;&gt;/// Tests for Common Logging extensions that use Caller Information&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  10:  &lt;/span&gt;    &lt;span class=&quot;rem&quot;&gt;/// https://msdn.microsoft.com/en-us/library/mt653988.aspx&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  11:  &lt;/span&gt;    &lt;span class=&quot;rem&quot;&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  12:  &lt;/span&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; LogCallTests&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  13:  &lt;/span&gt;    {&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  14:  &lt;/span&gt;        [Fact]&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  15:  &lt;/span&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; LogFromMethod()&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  16:  &lt;/span&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  17:  &lt;/span&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; log = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; QueueSimpleLogger();&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  18:  &lt;/span&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; ex = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Exception(&lt;span class=&quot;str&quot;&gt;&quot;Boom&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  19:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  20:  &lt;/span&gt;            log.Debug(&lt;span class=&quot;str&quot;&gt;&quot;Hello&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  21:  &lt;/span&gt;            log.Debug(&lt;span class=&quot;str&quot;&gt;&quot;World&quot;&lt;/span&gt;, ex);&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  22:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  23:  &lt;/span&gt;            log.DebugCall(&lt;span class=&quot;str&quot;&gt;&quot;Hello&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  24:  &lt;/span&gt;            log.DebugCall(&lt;span class=&quot;str&quot;&gt;&quot;World&quot;&lt;/span&gt;, ex);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  25:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  26:  &lt;/span&gt;            log.WarnFormat(&lt;span class=&quot;str&quot;&gt;&quot;Hello - {0}&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;Zero&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  27:  &lt;/span&gt;            log.WarnFormat(&lt;span class=&quot;str&quot;&gt;&quot;World - {0}&quot;&lt;/span&gt;, ex, &lt;span class=&quot;str&quot;&gt;&quot;Zero&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  28:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  29:  &lt;/span&gt;            log.WarnFormatCall(&lt;span class=&quot;str&quot;&gt;&quot;Hello - {0}&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;Zero&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  30:  &lt;/span&gt;            log.WarnFormatCall(&lt;span class=&quot;str&quot;&gt;&quot;World - {0}&quot;&lt;/span&gt;, ex, &lt;span class=&quot;str&quot;&gt;&quot;Zero&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  31:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  32:  &lt;/span&gt;            Assert.Equal(8, log.Queue.Count);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  33:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  34:  &lt;/span&gt;            Assert.Equal(&lt;span class=&quot;str&quot;&gt;&quot;Hello&quot;&lt;/span&gt;, log.Queue.Dequeue());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  35:  &lt;/span&gt;            Assert.Equal(&lt;span class=&quot;str&quot;&gt;&quot;World - Ex: Boom&quot;&lt;/span&gt;, log.Queue.Dequeue());&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  36:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  37:  &lt;/span&gt;            Assert.Equal(&lt;span class=&quot;str&quot;&gt;&quot;LogCallTests.LogFromMethod(23) - Hello&quot;&lt;/span&gt;, log.Queue.Dequeue());&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  38:  &lt;/span&gt;            Assert.Equal(&lt;span class=&quot;str&quot;&gt;&quot;LogCallTests.LogFromMethod(24) - World - Ex: Boom&quot;&lt;/span&gt;, log.Queue.Dequeue());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  39:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  40:  &lt;/span&gt;            Assert.Equal(&lt;span class=&quot;str&quot;&gt;&quot;Hello - Zero&quot;&lt;/span&gt;, log.Queue.Dequeue());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  41:  &lt;/span&gt;            Assert.Equal(&lt;span class=&quot;str&quot;&gt;&quot;World - Zero - Ex: Boom&quot;&lt;/span&gt;, log.Queue.Dequeue());&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  42:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  43:  &lt;/span&gt;            Assert.Equal(&lt;span class=&quot;str&quot;&gt;&quot;LogCallTests.LogFromMethod(29) - Hello - Zero&quot;&lt;/span&gt;, log.Queue.Dequeue());&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  44:  &lt;/span&gt;            Assert.Equal(&lt;span class=&quot;str&quot;&gt;&quot;LogCallTests.LogFromMethod(30) - World - Zero - Ex: Boom&quot;&lt;/span&gt;, log.Queue.Dequeue());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  45:  &lt;/span&gt;        }&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  46:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  47:  &lt;/span&gt;        [Fact]&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  48:  &lt;/span&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; LogFromAction()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  49:  &lt;/span&gt;        {&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  50:  &lt;/span&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; log = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; QueueSimpleLogger();&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  51:  &lt;/span&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; ex = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Exception(&lt;span class=&quot;str&quot;&gt;&quot;Boom&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  52:  &lt;/span&gt;            Action action = () =&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  53:  &lt;/span&gt;            {&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  54:  &lt;/span&gt;                log.Debug(&lt;span class=&quot;str&quot;&gt;&quot;Hello&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  55:  &lt;/span&gt;                log.Debug(&lt;span class=&quot;str&quot;&gt;&quot;World&quot;&lt;/span&gt;, ex);&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  56:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  57:  &lt;/span&gt;                log.DebugCall(&lt;span class=&quot;str&quot;&gt;&quot;Hello&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  58:  &lt;/span&gt;                log.DebugCall(&lt;span class=&quot;str&quot;&gt;&quot;World&quot;&lt;/span&gt;, ex);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  59:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  60:  &lt;/span&gt;                log.WarnFormat(&lt;span class=&quot;str&quot;&gt;&quot;Hello - {0}&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;Zero&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  61:  &lt;/span&gt;                log.WarnFormat(&lt;span class=&quot;str&quot;&gt;&quot;World - {0}&quot;&lt;/span&gt;, ex, &lt;span class=&quot;str&quot;&gt;&quot;Zero&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  62:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  63:  &lt;/span&gt;                log.WarnFormatCall(&lt;span class=&quot;str&quot;&gt;&quot;Hello - {0}&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;Zero&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  64:  &lt;/span&gt;                log.WarnFormatCall(&lt;span class=&quot;str&quot;&gt;&quot;World - {0}&quot;&lt;/span&gt;, ex, &lt;span class=&quot;str&quot;&gt;&quot;Zero&quot;&lt;/span&gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  65:  &lt;/span&gt;            };&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  66:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  67:  &lt;/span&gt;            action();&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  68:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  69:  &lt;/span&gt;            Assert.Equal(8, log.Queue.Count);&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  70:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  71:  &lt;/span&gt;            Assert.Equal(&lt;span class=&quot;str&quot;&gt;&quot;Hello&quot;&lt;/span&gt;, log.Queue.Dequeue());&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  72:  &lt;/span&gt;            Assert.Equal(&lt;span class=&quot;str&quot;&gt;&quot;World - Ex: Boom&quot;&lt;/span&gt;, log.Queue.Dequeue());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  73:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  74:  &lt;/span&gt;            Assert.Equal(&lt;span class=&quot;str&quot;&gt;&quot;LogCallTests.LogFromAction(57) - Hello&quot;&lt;/span&gt;, log.Queue.Dequeue());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  75:  &lt;/span&gt;            Assert.Equal(&lt;span class=&quot;str&quot;&gt;&quot;LogCallTests.LogFromAction(58) - World - Ex: Boom&quot;&lt;/span&gt;, log.Queue.Dequeue());&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  76:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  77:  &lt;/span&gt;            Assert.Equal(&lt;span class=&quot;str&quot;&gt;&quot;Hello - Zero&quot;&lt;/span&gt;, log.Queue.Dequeue());&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  78:  &lt;/span&gt;            Assert.Equal(&lt;span class=&quot;str&quot;&gt;&quot;World - Zero - Ex: Boom&quot;&lt;/span&gt;, log.Queue.Dequeue());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  79:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  80:  &lt;/span&gt;            Assert.Equal(&lt;span class=&quot;str&quot;&gt;&quot;LogCallTests.LogFromAction(63) - Hello - Zero&quot;&lt;/span&gt;, log.Queue.Dequeue());&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  81:  &lt;/span&gt;            Assert.Equal(&lt;span class=&quot;str&quot;&gt;&quot;LogCallTests.LogFromAction(64) - World - Zero - Ex: Boom&quot;&lt;/span&gt;, log.Queue.Dequeue());&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  82:  &lt;/span&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  83:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  84:  &lt;/span&gt;        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; QueueSimpleLogger : AbstractSimpleLogger&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  85:  &lt;/span&gt;        {&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  86:  &lt;/span&gt;            &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;readonly&lt;/span&gt; Queue&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt; Queue = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Queue&amp;lt;&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;&amp;gt;(); &lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  87:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  88:  &lt;/span&gt;            &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; QueueSimpleLogger()&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  89:  &lt;/span&gt;                : &lt;span class=&quot;kwrd&quot;&gt;base&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.Empty, LogLevel.All, &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;true&lt;/span&gt;, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt;.Empty)&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  90:  &lt;/span&gt;            {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  91:  &lt;/span&gt;            }&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  92:  &lt;/span&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  93:  &lt;/span&gt;            &lt;span class=&quot;kwrd&quot;&gt;protected&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;override&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; WriteInternal(LogLevel level, &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; message, Exception exception)&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  94:  &lt;/span&gt;            {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  95:  &lt;/span&gt;                &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; s = message.ToString();&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  96:  &lt;/span&gt;                &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (exception != &lt;span class=&quot;kwrd&quot;&gt;null&lt;/span&gt;) s += &lt;span class=&quot;str&quot;&gt;&quot; - Ex: &quot;&lt;/span&gt; + exception.Message;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  97:  &lt;/span&gt;                Queue.Enqueue(s);&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt;  98:  &lt;/span&gt;            }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt;  99:  &lt;/span&gt;        }&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;lnum&quot;&gt; 100:  &lt;/span&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;lnum&quot;&gt; 101:  &lt;/span&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;a name=&#39;more&#39;&gt;&lt;/a&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;LogExtension.cs (Part of a Generated File)&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; System.Runtime.CompilerServices;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; System.Text.RegularExpressions;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;rem&quot;&gt;// ReSharper disable once CheckNamespace&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;kwrd&quot;&gt;namespace&lt;/span&gt; Common.Logging&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; LogExtensions&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; Regex ClassNameRegex = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Regex(&lt;span class=&quot;str&quot;&gt;@&quot;([\w]+)\.[\w]+$&quot;&lt;/span&gt;, RegexOptions.Compiled);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;/* ... */&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; DebugCall(&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt; ILog log,&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; message,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            BreakParameter breakParameter = &lt;span class=&quot;kwrd&quot;&gt;default&lt;/span&gt;(BreakParameter),&lt;/pre&gt;
&lt;pre&gt;            [CallerMemberName] &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; memberName = &lt;span class=&quot;str&quot;&gt;&quot;&quot;&lt;/span&gt;,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            [CallerFilePath] &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; sourceFilePath = &lt;span class=&quot;str&quot;&gt;&quot;&quot;&lt;/span&gt;,&lt;/pre&gt;
&lt;pre&gt;            [CallerLineNumber] &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; sourceLineNumber = 0)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!log.IsDebugEnabled) &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; newFormat = GetFormat(message.ToString(), memberName, sourceFilePath, sourceLineNumber);&lt;/pre&gt;
&lt;pre&gt;            log.Debug(&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                newFormat);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; DebugCall(&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt; ILog log,&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; message,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            Exception ex,&lt;/pre&gt;
&lt;pre&gt;            BreakParameter breakParameter = &lt;span class=&quot;kwrd&quot;&gt;default&lt;/span&gt;(BreakParameter),&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            [CallerMemberName] &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; memberName = &lt;span class=&quot;str&quot;&gt;&quot;&quot;&lt;/span&gt;,&lt;/pre&gt;
&lt;pre&gt;            [CallerFilePath] &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; sourceFilePath = &lt;span class=&quot;str&quot;&gt;&quot;&quot;&lt;/span&gt;,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            [CallerLineNumber] &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; sourceLineNumber = 0)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!log.IsDebugEnabled) &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; newFormat = GetFormat(message.ToString(), memberName, sourceFilePath, sourceLineNumber);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            log.Debug(&lt;/pre&gt;
&lt;pre&gt;                newFormat,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                ex);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; DebugFormatCall(&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt; ILog log,&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; format,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; arg0,&lt;/pre&gt;
&lt;pre&gt;            BreakParameter breakParameter = &lt;span class=&quot;kwrd&quot;&gt;default&lt;/span&gt;(BreakParameter),&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            [CallerMemberName] &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; memberName = &lt;span class=&quot;str&quot;&gt;&quot;&quot;&lt;/span&gt;,&lt;/pre&gt;
&lt;pre&gt;            [CallerFilePath] &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; sourceFilePath = &lt;span class=&quot;str&quot;&gt;&quot;&quot;&lt;/span&gt;,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            [CallerLineNumber] &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; sourceLineNumber = 0)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!log.IsDebugEnabled) &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; newFormat = GetFormat(format, memberName, sourceFilePath, sourceLineNumber);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            log.DebugFormat(&lt;/pre&gt;
&lt;pre&gt;                newFormat,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                arg0);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; DebugFormatCall(&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt; ILog log,&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; format,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            Exception ex,&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; arg0,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            BreakParameter breakParameter = &lt;span class=&quot;kwrd&quot;&gt;default&lt;/span&gt;(BreakParameter),&lt;/pre&gt;
&lt;pre&gt;            [CallerMemberName] &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; memberName = &lt;span class=&quot;str&quot;&gt;&quot;&quot;&lt;/span&gt;,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            [CallerFilePath] &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; sourceFilePath = &lt;span class=&quot;str&quot;&gt;&quot;&quot;&lt;/span&gt;,&lt;/pre&gt;
&lt;pre&gt;            [CallerLineNumber] &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; sourceLineNumber = 0)&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        {&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!log.IsDebugEnabled) &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; newFormat = GetFormat(format, memberName, sourceFilePath, sourceLineNumber);&lt;/pre&gt;
&lt;pre&gt;            log.DebugFormat(&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                newFormat,&lt;/pre&gt;
&lt;pre&gt;                ex,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                arg0);&lt;/pre&gt;
&lt;pre&gt;        }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;rem&quot;&gt;/* ... */&lt;/span&gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;        [MethodImpl(MethodImplOptions.AggressiveInlining)]&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; GetFormat(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; format, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; memberName, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; sourceFilePath, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; sourceLineNumber)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; m = ClassNameRegex.Match(sourceFilePath);&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; m.Success&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                ? $&lt;span class=&quot;str&quot;&gt;&quot;{m.Groups[1].Value}.{memberName}({sourceLineNumber}) - {format}&quot;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;                : format;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;struct&lt;/span&gt; BreakParameter&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;h3 style=&quot;margin-top:20px; margin-bottom:15px;&quot;&gt;LogExtension.tt (T4 Template)&lt;/h3&gt;

&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;div class=&quot;csharpcode&quot;&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;lt;#@ template debug=&lt;span class=&quot;str&quot;&gt;&quot;false&quot;&lt;/span&gt; hostspecific=&lt;span class=&quot;str&quot;&gt;&quot;false&quot;&lt;/span&gt; language=&lt;span class=&quot;str&quot;&gt;&quot;C#&quot;&lt;/span&gt; #&amp;gt;&lt;/pre&gt;
&lt;pre&gt;&amp;lt;#@ assembly name=&lt;span class=&quot;str&quot;&gt;&quot;System.Core&quot;&lt;/span&gt; #&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;lt;#@ import &lt;span class=&quot;kwrd&quot;&gt;namespace&lt;/span&gt;=&lt;span class=&quot;str&quot;&gt;&quot;System.Linq&quot;&lt;/span&gt; #&amp;gt;&lt;/pre&gt;
&lt;pre&gt;&amp;lt;#@ import &lt;span class=&quot;kwrd&quot;&gt;namespace&lt;/span&gt;=&lt;span class=&quot;str&quot;&gt;&quot;System.Text&quot;&lt;/span&gt; #&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;lt;#@ import &lt;span class=&quot;kwrd&quot;&gt;namespace&lt;/span&gt;=&lt;span class=&quot;str&quot;&gt;&quot;System.Collections.Generic&quot;&lt;/span&gt; #&amp;gt;&lt;/pre&gt;
&lt;pre&gt;&amp;lt;#@ output extension=&lt;span class=&quot;str&quot;&gt;&quot;.cs&quot;&lt;/span&gt; #&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; System;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; System.Runtime.CompilerServices;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;kwrd&quot;&gt;using&lt;/span&gt; System.Text.RegularExpressions;&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&lt;span class=&quot;rem&quot;&gt;// ReSharper disable once CheckNamespace&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;span class=&quot;kwrd&quot;&gt;namespace&lt;/span&gt; Common.Logging&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;{&lt;/pre&gt;
&lt;pre&gt;    &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;class&lt;/span&gt; LogExtensions&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;    {&lt;/pre&gt;
&lt;pre&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; Regex ClassNameRegex = &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; Regex(&lt;span class=&quot;str&quot;&gt;@&quot;([\w]+)\.[\w]+$&quot;&lt;/span&gt;, RegexOptions.Compiled);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre&gt;&amp;lt;# &lt;span class=&quot;kwrd&quot;&gt;foreach&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; level &lt;span class=&quot;kwrd&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;new&lt;/span&gt; [] { &lt;span class=&quot;str&quot;&gt;&quot;Trace&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;Debug&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;Info&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;Warn&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;Error&quot;&lt;/span&gt;, &lt;span class=&quot;str&quot;&gt;&quot;Fatal&quot;&lt;/span&gt; }) { #&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;lt;# &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; argCount = 0; argCount &amp;lt;= 8; argCount++) { #&amp;gt;&lt;/pre&gt;
&lt;pre&gt;&amp;lt;# &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; suffix = argCount == 0 ? &lt;span class=&quot;str&quot;&gt;&quot;&quot;&lt;/span&gt; : &lt;span class=&quot;str&quot;&gt;&quot;Format&quot;&lt;/span&gt;; #&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;lt;# &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; varType = argCount == 0 ? &lt;span class=&quot;str&quot;&gt;&quot;object&quot;&lt;/span&gt; : &lt;span class=&quot;str&quot;&gt;&quot;string&quot;&lt;/span&gt;; #&amp;gt;&lt;/pre&gt;
&lt;pre&gt;&amp;lt;# &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; varName = argCount == 0 ? &lt;span class=&quot;str&quot;&gt;&quot;message&quot;&lt;/span&gt; : &lt;span class=&quot;str&quot;&gt;&quot;format&quot;&lt;/span&gt;; #&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;lt;# &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; vartoString = argCount == 0 ? &lt;span class=&quot;str&quot;&gt;&quot;.ToString()&quot;&lt;/span&gt; : &lt;span class=&quot;str&quot;&gt;&quot;&quot;&lt;/span&gt;; #&amp;gt;&lt;/pre&gt;
&lt;pre&gt;&amp;lt;# &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; hasException = 0; hasException &amp;lt; 2; hasException++) { #&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;void&lt;/span&gt; &amp;lt;#= level #&amp;gt;&amp;lt;#= suffix #&amp;gt;Call(&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;this&lt;/span&gt; ILog log,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &amp;lt;#= varType #&amp;gt; &amp;lt;#= varName #&amp;gt;,&lt;/pre&gt;
&lt;pre&gt;&amp;lt;# &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (hasException == 1) { #&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            Exception ex,&lt;/pre&gt;
&lt;pre&gt;&amp;lt;# } #&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;lt;# &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; argCount; i++) { #&amp;gt;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;object&lt;/span&gt; arg&amp;lt;#= i #&amp;gt;,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;lt;# } #&amp;gt;&lt;/pre&gt;
&lt;pre&gt;            BreakParameter breakParameter = &lt;span class=&quot;kwrd&quot;&gt;default&lt;/span&gt;(BreakParameter),&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            [CallerMemberName] &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; memberName = &lt;span class=&quot;str&quot;&gt;&quot;&quot;&lt;/span&gt;,&lt;/pre&gt;
&lt;pre&gt;            [CallerFilePath] &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; sourceFilePath = &lt;span class=&quot;str&quot;&gt;&quot;&quot;&lt;/span&gt;,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            [CallerLineNumber] &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; sourceLineNumber = 0)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (!log.Is&amp;lt;#= level #&amp;gt;Enabled) &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt;;&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; newFormat = GetFormat(&amp;lt;#= varName #&amp;gt;&amp;lt;#= vartoString #&amp;gt;, memberName, sourceFilePath, sourceLineNumber);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            log.&amp;lt;#= level #&amp;gt;&amp;lt;#= suffix #&amp;gt;(&lt;/pre&gt;
&lt;pre&gt;                newFormat&amp;lt;# &lt;span class=&quot;kwrd&quot;&gt;if&lt;/span&gt; (hasException == 1) { #&amp;gt;,&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                ex&amp;lt;# } #&amp;gt;&amp;lt;# &lt;span class=&quot;kwrd&quot;&gt;for&lt;/span&gt;(&lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; i = 0; i &amp;lt; argCount; i++) { #&amp;gt;,&lt;/pre&gt;
&lt;pre&gt;                arg&amp;lt;#= i #&amp;gt;&amp;lt;# } #&amp;gt;);&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;lt;# } #&amp;gt;&lt;/pre&gt;
&lt;pre&gt;&amp;lt;# } #&amp;gt;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;&amp;lt;# } #&amp;gt;&lt;/pre&gt;
&lt;pre&gt;        [MethodImpl(MethodImplOptions.AggressiveInlining)]&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; GetFormat(&lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; format, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; memberName, &lt;span class=&quot;kwrd&quot;&gt;string&lt;/span&gt; sourceFilePath, &lt;span class=&quot;kwrd&quot;&gt;int&lt;/span&gt; sourceLineNumber)&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;            &lt;span class=&quot;kwrd&quot;&gt;var&lt;/span&gt; m = ClassNameRegex.Match(sourceFilePath);&lt;/pre&gt;
&lt;pre&gt;            &lt;span class=&quot;kwrd&quot;&gt;return&lt;/span&gt; m.Success&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;                ? $&lt;span class=&quot;str&quot;&gt;&quot;{m.Groups[1].Value}.{memberName}({sourceLineNumber}) - {format}&quot;&lt;/span&gt;&lt;/pre&gt;
&lt;pre&gt;                : format;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        &lt;span class=&quot;kwrd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kwrd&quot;&gt;struct&lt;/span&gt; BreakParameter&lt;/pre&gt;
&lt;pre&gt;        {&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;        }&lt;/pre&gt;
&lt;pre&gt;    }&lt;/pre&gt;
&lt;pre class=&quot;alt&quot;&gt;}&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Enjoy,&lt;br&gt;Tom&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.tomdupont.net/feeds/9035201734653449117/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.tomdupont.net/2016/05/common-logging-extensions-with-caller.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/9035201734653449117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4063545436138319205/posts/default/9035201734653449117'/><link rel='alternate' type='text/html' href='http://www.tomdupont.net/2016/05/common-logging-extensions-with-caller.html' title='Common Logging Extensions with Caller Information'/><author><name>Tom DuPont</name><uri>http://www.blogger.com/profile/08233783264428691459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='//blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgd_HcsnIp0zc1qtAs7Gm-hfoETw10jmM1qNf8-a3__pnyq0Mj1Ezzyna0pyGfqLcwL3FKLeKqwWDhANmprBH2HTaoMfaNA2WlITrY0dWpcghTyWJ8YBZITN5SlmpddOdA/s220/tom_dupont.png'/></author><thr:total>0</thr:total></entry></feed>