Note that there are some explanatory texts on larger screens.

plurals
  1. PO"Uncurrying" an instance method in .NET
    primarykey
    data
    text
    <p>Can you create a delegate of an instance method without specifying the instance at creation time? In other words, can you create a "static" delegate that takes as it's first parameter the instance the method should be called on?</p> <p>For example, how can I construct the following delegate using reflection?</p> <pre><code>Func&lt;int, string&gt; = i=&gt;i.ToString(); </code></pre> <p>I'm aware of the fact that I can use methodInfo.Invoke, but this is slower, and does not check for type-correctness until it is called.</p> <p>When you have the <code>MethodInfo</code> of a particular <em>static</em> method, it is possible to construct a delegate using <code>Delegate.CreateDelegate(delegateType, methodInfo)</code>, and all parameters of the static method remain free.</p> <p>As Jon Skeet pointed out, you can simply apply the same to make an open delegate of an instance method if the method is non-virtual on a reference type. Deciding which method to call on a virtual method is tricky, so that's no so trivial, and value-types look like they don't work at all.</p> <p>For value types, <code>CreateDelegate</code> exhibits really weird behavior:</p> <pre><code>var func37 = (Func&lt;CultureInfo,string&gt;)(37.ToString); var toStringMethod = typeof(int).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public, null, new Type[] {typeof(CultureInfo) }, null); var func42 = (Func&lt;CultureInfo,string&gt;)Delegate.CreateDelegate(typeof(Func&lt;CultureInfo,string&gt;), 42, toStringMethod,true); Console.WriteLine( object.ReferenceEquals(func37.Method,func42.Method)); //true Console.WriteLine(func37.Target);//37 Console.WriteLine(func42.Target);//42 Console.WriteLine(func37(CultureInfo.InvariantCulture));//37 Console.WriteLine(func42(CultureInfo.InvariantCulture));//-201040128... WTF? </code></pre> <p>Calling <code>CreateDelegate</code> with <code>null</code> as the target object throws a binding exception if the instance method belonged to a value type (this works for reference types).</p> <p><em>Some follow-up years later:</em> The incorrectly-bound target that caused <code>func42(CultureInfo.InvariantCulture);</code> to return <code>"-201040128"</code> instead of <code>"42"</code> in my example was memory corruption that could have allowed remote code execution (<a href="http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=cve-2010-1898" rel="nofollow noreferrer">cve-2010-1898</a>); this was fixed in 2010 in the <a href="https://docs.microsoft.com/en-us/security-updates/securitybulletins/2010/ms10-060" rel="nofollow noreferrer">ms10-060</a> security update. Current frameworks correctly print 42! That doesn't make answering this question any easier, but explains the particularly weird behavior in the example.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

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

Reload