<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="https://shazwazza.com/rss/xslt"?>
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title>Shazwazza</title>
    <link>https://shazwazza.com/</link>
    <description>My blog which is pretty much just all about coding</description>
    <generator>Articulate, blogging built on Umbraco</generator>
    <image>
      <url>/media/0libq25y/frog.png?rmode=max&amp;v=1da0e911f4e6890</url>
      <title>Shazwazza</title>
      <link>https://shazwazza.com/</link>
    </image>
    <item>
      <guid isPermaLink="false">1178</guid>
      <link>https://shazwazza.com/post/making-a-dynamicobject-implementation-be-case-insensitive/</link>
      <category>ASP.Net</category>
      <title>Making a DynamicObject implementation be case insensitive</title>
      <description>&lt;p&gt;To me this seems to be a very straight forward request but I cannot find the ‘easy’ way to do this in .Net even though there seems to be a clear indication that this is supported Out of The Box. Here’s an example of what I want to do:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;//Simple class&lt;/span&gt;
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Foo
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Hello {get;set;}
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; World {get;set;}
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; AddNumbers(&lt;span class="kwrd"&gt;int&lt;/span&gt; num1, &lt;span class="kwrd"&gt;int&lt;/span&gt; num2)
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; num1 + num2;
    }
}

&lt;span class="rem"&gt;//Use the simple class but allow case insensitive&lt;/span&gt;
&lt;span class="rem"&gt;// access to it's properties and members&lt;/span&gt;
var foo = &lt;span class="kwrd"&gt;new&lt;/span&gt; Foo{ Hello = &lt;span class="str"&gt;"hi"&lt;/span&gt;, World = &lt;span class="str"&gt;"earth"&lt;/span&gt; };

&lt;span class="rem"&gt;//make it dynamic&lt;/span&gt;
dynamic dFoo = foo;

&lt;span class="rem"&gt;//access the dynamic object's props and methods &lt;/span&gt;
&lt;span class="rem"&gt;// in a case insensitive way:&lt;/span&gt;
Assert.AreEqual(foo.Hello, dFoo.hello);
Assert.AreEqual(foo.World, dFoo.world);
Assert.AreEqual(foo.AddNumbers(1,2), dFoo.addNumbers(1,2));&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;h2&gt;DynamicObject&lt;/h2&gt;
&lt;p&gt;In order to do the above, you can implement ‘&lt;em&gt;DynamicObject’&lt;/em&gt; and override a couple of methods:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Foo : DynamicObject
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Hello {get;set;}
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; World {get;set;}
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; AddNumbers(&lt;span class="kwrd"&gt;int&lt;/span&gt; num1, &lt;span class="kwrd"&gt;int&lt;/span&gt; num2)
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; num1 + num2;
    }
    
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; TryInvokeMember(InvokeMemberBinder binder, &lt;span class="kwrd"&gt;object&lt;/span&gt;[] args, &lt;span class="kwrd"&gt;out&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; result)
    {
        &lt;span class="rem"&gt;//Here we would need to match lower cased binder.Name&lt;/span&gt;
        &lt;span class="rem"&gt;// to a real method that our object has&lt;/span&gt;
        var name = binder.Name.ToLowerInvariant();
        &lt;span class="rem"&gt;//TODO: Do the matching&lt;/span&gt;
        
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.TryInvokeMember(binder, args, &lt;span class="kwrd"&gt;out&lt;/span&gt; result);
    }
    
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; TryGetMember(GetMemberBinder binder, &lt;span class="kwrd"&gt;out&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; result)
    {
        &lt;span class="rem"&gt;//Here we would need to match lower cased binder.Name&lt;/span&gt;
        &lt;span class="rem"&gt;// to a real property that our object has&lt;/span&gt;
        var name = binder.Name.ToLowerInvariant();
        &lt;span class="rem"&gt;//TODO: Do the matching&lt;/span&gt;
        
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.TryGetMember(binder, &lt;span class="kwrd"&gt;out&lt;/span&gt; result);
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;I don’t know about you, but I’d rather not have to write all the code to do the matching and executing. This seems like a pretty straight forward thing to want to do and after looking at the innards of some of this stuff, it turns out that the ‘&lt;em&gt;GetMemberBinder’&lt;/em&gt; object has a property conveniently called `&lt;em&gt;IgnoreCase&lt;/em&gt;`… surely this functionality already exists!?&lt;/p&gt;
&lt;p&gt;Well I unfortunately cannot find anything worthwhile on Google about ‘&lt;em&gt;GetMemberBinder.IgnoreCase&lt;/em&gt;’, I also can’t really see where or how it gets used when looking at decompiled sources. &lt;/p&gt;
&lt;p&gt;So I’ve reverted to handling this on my own but I would really really really like to know if there’s a built in and simple way to do this in .Net since it sure seems like it should exist.&lt;/p&gt;
&lt;h2&gt;CaseInsensitiveDynamicObject&lt;/h2&gt;
&lt;p&gt;This is a base class implementation to achieve what I want. It’s not error proof and I’m sure with some objects it won’t work 100% as expected but for simple objects this will work. Using this implementation is super easy:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; Foo : CaseInsensitiveDynamicObject
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Hello {get;set;}
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; World {get;set;}
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;int&lt;/span&gt; AddNumbers(&lt;span class="kwrd"&gt;int&lt;/span&gt; num1, &lt;span class="kwrd"&gt;int&lt;/span&gt; num2)
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; num1 + num2;
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;By doing that, my original requirement works! Here’s the code that does this … because I was lazy and didn’t want to create more classes than I needed I’m using Tuples so the code is fully of super generic fun ;)&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span class="rem"&gt;/// This will check enable dynamic access to properties and methods in a case insensitive manner&lt;/span&gt;
&lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span class="rem"&gt;/// &amp;lt;typeparam name="T"&amp;gt;&amp;lt;/typeparam&amp;gt;&lt;/span&gt;
&lt;span class="rem"&gt;/// &amp;lt;remarks&amp;gt;&lt;/span&gt;
&lt;span class="rem"&gt;/// This works by using reflection on the type - the reflection lookup is lazy so it will not execute unless a dynamic method needs to be accessed&lt;/span&gt;
&lt;span class="rem"&gt;/// &amp;lt;/remarks&amp;gt;&lt;/span&gt;
&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CaseInsensitiveDynamicObject&amp;lt;T&amp;gt; : DynamicObject
    &lt;span class="kwrd"&gt;where&lt;/span&gt; T: &lt;span class="kwrd"&gt;class&lt;/span&gt;
{
    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Used for dynamic access for case insensitive property access&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;`&lt;/span&gt;
    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; Lazy&amp;lt;IDictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, Func&amp;lt;T, &lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;&amp;gt;&amp;gt; CaseInsensitivePropertyAccess = &lt;span class="kwrd"&gt;new&lt;/span&gt; Lazy&amp;lt;IDictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, Func&amp;lt;T, &lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;&amp;gt;&amp;gt;(() =&amp;gt;
    {
        var props = &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(T).GetProperties(BindingFlags.Instance | BindingFlags.Public)
            .DistinctBy(x =&amp;gt; x.Name);
        &lt;span class="kwrd"&gt;return&lt;/span&gt; props.Select(propInfo =&amp;gt;
        {
            var name = propInfo.Name.ToLowerInvariant();
            Func&amp;lt;T, &lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt; getVal = propInfo.GetValue;
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; KeyValuePair&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, Func&amp;lt;T, &lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;&amp;gt;(name, getVal);

        }).ToDictionary(x =&amp;gt; x.Key, x =&amp;gt; x.Value);
    });

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Used for dynamic access for case insensitive property access&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; Lazy&amp;lt;IDictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, Tuple&amp;lt;ParameterInfo[], Func&amp;lt;T, &lt;span class="kwrd"&gt;object&lt;/span&gt;[], &lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; CaseInsensitiveMethodAccess
        = &lt;span class="kwrd"&gt;new&lt;/span&gt; Lazy&amp;lt;IDictionary&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, Tuple&amp;lt;ParameterInfo[], Func&amp;lt;T, &lt;span class="kwrd"&gt;object&lt;/span&gt;[], &lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;(() =&amp;gt;
        {
            var props = &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(T).GetMethods(BindingFlags.Instance | BindingFlags.Public)
                .Where(x =&amp;gt; x.IsSpecialName == &lt;span class="kwrd"&gt;false&lt;/span&gt; &amp;amp;&amp;amp; x.IsVirtual == &lt;span class="kwrd"&gt;false&lt;/span&gt;)
                .DistinctBy(x =&amp;gt; x.Name);
            &lt;span class="kwrd"&gt;return&lt;/span&gt; props.Select(methodInfo =&amp;gt;
            {
                var name = methodInfo.Name.ToLowerInvariant();
                Func&amp;lt;T, &lt;span class="kwrd"&gt;object&lt;/span&gt;[], &lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt; getVal = methodInfo.Invoke;
                var val = &lt;span class="kwrd"&gt;new&lt;/span&gt; Tuple&amp;lt;ParameterInfo[], Func&amp;lt;T, &lt;span class="kwrd"&gt;object&lt;/span&gt;[], &lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;&amp;gt;(methodInfo.GetParameters(), getVal);
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; KeyValuePair&amp;lt;&lt;span class="kwrd"&gt;string&lt;/span&gt;, Tuple&amp;lt;ParameterInfo[], Func&amp;lt;T, &lt;span class="kwrd"&gt;object&lt;/span&gt;[], &lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;&amp;gt;&amp;gt;(name, val);

            }).ToDictionary(x =&amp;gt; x.Key, x =&amp;gt; x.Value);
        });

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Used for dynamic access for case insensitive method access&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; TryInvokeMember(InvokeMemberBinder binder, &lt;span class="kwrd"&gt;object&lt;/span&gt;[] args, &lt;span class="kwrd"&gt;out&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; result)
    {
        var name = binder.Name.ToLowerInvariant();
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (CaseInsensitiveMethodAccess.Value.ContainsKey(name) == &lt;span class="kwrd"&gt;false&lt;/span&gt;)
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.TryInvokeMember(binder, args, &lt;span class="kwrd"&gt;out&lt;/span&gt; result);

        var val = CaseInsensitiveMethodAccess.Value[name];
        var parameters = val.Item1;
        var callback = val.Item2;
        var fullArgs = &lt;span class="kwrd"&gt;new&lt;/span&gt; List&amp;lt;&lt;span class="kwrd"&gt;object&lt;/span&gt;&amp;gt;(args);
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (args.Length &amp;lt;= parameters.Length)
        {
            &lt;span class="rem"&gt;//need to fill them up if they're optional&lt;/span&gt;
            &lt;span class="kwrd"&gt;for&lt;/span&gt; (var i = args.Length; i &amp;lt; parameters.Length; i++)
            {
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (parameters[i].IsOptional)
                {
                    fullArgs.Add(parameters[i].DefaultValue);
                }
            }
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (fullArgs.Count == parameters.Length)
            {
                result = callback((T)(&lt;span class="kwrd"&gt;object&lt;/span&gt;)&lt;span class="kwrd"&gt;this&lt;/span&gt;, fullArgs.ToArray());
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;
            }
        }
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.TryInvokeMember(binder, args, &lt;span class="kwrd"&gt;out&lt;/span&gt; result);
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; TryGetMember(GetMemberBinder binder, &lt;span class="kwrd"&gt;out&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; result)
    {
        var name = binder.Name.ToLowerInvariant();
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (CaseInsensitivePropertyAccess.Value.ContainsKey(name) == &lt;span class="kwrd"&gt;false&lt;/span&gt;)
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.TryGetMember(binder, &lt;span class="kwrd"&gt;out&lt;/span&gt; result);

        result = CaseInsensitivePropertyAccess.Value[name]((T)(&lt;span class="kwrd"&gt;object&lt;/span&gt;)&lt;span class="kwrd"&gt;this&lt;/span&gt;);
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;
    }
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;If anyone know how to make this work OOTB with .Net, perhaps using the `&lt;em&gt;GetMemberBinder.IgnoreCase`&lt;/em&gt; I’d love to hear it!&lt;/p&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:15 Z</pubDate>
      <a10:updated>2023-03-23T15:08:15Z</a10:updated>
    </item>
  </channel>
</rss>