Create a static delegate from a non-static method

I need to create a delegate for a non-static class method. The difficulty lies in the fact that at the time of creation I do not have a class, only its definition of a class. During the conversation, I have a copy at hand. So I need a way:

  • Build an "incomplete" delegate to the member method, without an instance.
  • Call a delegate from 1, explicitly passing the intance of the class.

Are both options possible? How? Note. I am willing to pay a high price for number one, but ideally 2 should not be much more expensive than calling a delegate.

+4
source share
5 answers

You have two options, you can consider it in the same way as the extension method. Create a delegate to take the object and any optional arguments and pass those arguments to the actual function call. Or create one using Delegate.CreateInstance , as Dan mentioned.

eg.

 string s = "foobar"; // "extension method" approach Func<string, int, string> substring1 = (s, startIndex) => s.Substring(startIndex); substring1(s, 1); // "oobar" // using Delegate.CreateDelegate var stype = typeof(string); var mi = stype.GetMethod("Substring", new[] { typeof(int) }); var substring2 = (Func<string, int, string>)Delegate.CreateDelegate(typeof(Func<string, int, string>), mi); substring2(s, 2); // "obar" // it isn't even necessary to obtain the MethodInfo, the overload will determine // the appropriate method from the delegate type and name (as done in example 2). var substring3 = (Func<int, string>)Delegate.CreateDelegate(typeof(Func<int, string>), s, "Substring"); substring3(3); // "bar" // for a static method var compare = (Func<string, string, int>)Delegate.CreateDelegate(typeof(Func<string, string, int>), typeof(string), "Compare"); compare(s, "zoobar"); // -1 
+3
source

You can use Delegate.CreateDelegate to dynamically construct a delegate for a specific target instance, taking into account MethodInfo. You can search MethodInfo with Type.GetMethod (Reflection) and cache it for future use by creating a delegate.

For example, this will capture the GetHashCode method and bind it to the 'this' instance:

  var method = typeof(Object).GetMethod("GetHashCode"); var del = (Func<int>)Delegate.CreateDelegate(typeof(Func<int>), this, method); 

There are more subtleties if you have more than one method overload, but there are additional GetMethod parameters that you can use to disambiguate if necessary.

+4
source

What is wrong by simply passing the instance this way?

 // Creation. Action<Foo> bar = foo => { foo.Baz(); }; // Invocation. bar(new Foo()); 

It does everything you need: it encapsulates the logic you want to pass, and can be called on an arbitrary instance of the class.

Edit: if you are forbidden to use a delegate of a particular signature (not allowing the instance to be explicitly passed as a parameter), you can use some form of “instance provider” that is specified during delegate creation, but can be changed later to provide the corresponding instance when it will become available, for example:

 class Provider<T> { public T Instance { get; set; } } static Action Create(Provider<Foo> provider) { return () => { provider.Instance.Baz(); }; } // ... // Creation. var provider = new Provider<Foo>(); var bar = Create(provider); // Invocation. provider.Instance = new Foo(); bar(); 

Of course, this is a bit confusing and requires an additional object to transfer, so maybe it's not perfect!

+4
source

Despite the fact that this is an old post, what stands here is the third solution.

I was worried about the general problem of creating send tables, for example. static lookup tables for non-static methods. A typical use may be in ASP.NET event handling.

We would like the syntax and initialization to be as simple as possible. If the declaration and initialization of the send table is too complex, it would be easier / safer to simply write an explicit If-then-else-if or switch expression that sends the message.

We can declare a collection of delegates very simply. Assuming some methods Method1, Method2 and the delegate type SomeDelegate for them, then we can write:

 Dictionary<string, SomeDelegate> dispatchTable = new Dictionary<string, SomeDelegate> { { "Key1", Method1 } ,{ "Key2", Method2 } .... } 

In this case, we initialize the delegates using the method name directly.

While this works, unfortunately, it will not work as soon as we try to make dispatchTable a static member. This is because SomeDelegate is a private delegate (associated with an instance) and therefore cannot be initialized from a static scope. This is disappointing because our required mailings are known at compile time, so ideally we should set up a static send table.

As indicated in the selected solution in this thread, you can create open delegates via CreateDelegate, but this is syntactically inconvenient and also relies on passing the method name as a string to create the delegate so that you lose compile time checking. Declaring an offset table using this syntax would be very dirty.

The extension method method is less verbose and retains compile-time checking, but it is still inconvenient compared to the syntax above.

Another (third) option is to wrap the private delegates in a binding function, which, provided that the class instance returns the desired (closed) delegate. For example, you can use Func.

Then the dispatch table is basically:

 public class DispatchTable<Class, Key, Delegate> : Dictionary<Key, Func<Class, Delegate>> 

Assuming some methods called EventHandler1, EventHandler2 and the delegate type for them, for example.

 delegate int EventHandler(string param1, int param2); 

then declaring and initializing a static distribution table of non-static elements is as simple as:

 class MyDispatchTable : DispatchTable<MyClass, string, EventHandler> static MyDispatchTable dispatchTable = new MyDispatchTable { { "Event1", c => c.EventHandler1 } ,{ "Event2", c => c.EventHandler2 } }; 

Now the methods can be called through the distribution table taking into account the class instance, the key for the handler and the method parameters.

As an example, calling from a member function of the class itself, that is, an instance of the class = this, for the key k and parameters p1, p2, the syntax will look like this:

 var result = dispatchTable[key](this)(p1, p2); 

Note that this ignores appropriate error checking, for example. nonexistent keys. Error checking can be completed in the GetDelegate method in the DispatchTable class.

A complete example is given below. Note that it also includes a separate extension method for the Dictionary class to simplify the syntax for error handling.

Dictionary Extension:

  static public class DictionaryExtensions { // extension method to simplify accessing a dictionary static public V GetValueOrDefault<K, V>(this Dictionary<K, V> dict, K key) { V value; dict.TryGetValue(key, out value); return value; } } 

Dispatch table class:

  // Syntactic sugar for declaring a general dispatch table // The dictionary maps from a key to a function that can return // a closed delegate given an instance of a class. // Note that if keys are always integers then it is simpler to use an // array rather than a dictionary. public class DispatchTable<Key, Class, Delegate> : Dictionary<Key, Func<Class, Delegate>> { // standardise the method for accessing a delegate public Delegate GetDelegate(Class c, Key k) { var d = GetValueOrDefault(k); if (d == null) { throw new ArgumentException(String.Format("Delegate not found for key [{0}]",k)); } return d(c); } }; 

Usage example:

  public class Test { // some member functions to invoke public int EventHandler1(string param1, int param2) { return 1; } public int EventHandler2(string param1, int param2) { return 2; } // Declaration for a (closed) delegate for the member functions private delegate int EventHandler(string param1, int param2); // Syntactic sugar for declaring the table private class EventDispatchTable : DispatchTable<string, Test, EventHandler> { }; // Declare dispatch table and initialize static EventDispatchTable dispatchTable = new EventDispatchTable { { "Event1", c => c.EventHandler1 } ,{ "Event2", c => c.EventHandler2 } }; // Invoke via the dispatch table public int DoDispatch(string eventName, string param1, int param2) { return dispatchTable.GetDelegate(this, eventName)(param1, param2); } } 
+3
source

I'm five years late for the party, but I just ran into this problem and solved a slightly different solution:

 public class DelEx { private delegate void ProcessStuffDelegate(DelEx me); private static void ProcessStuffA(DelEx me) { me.ProcessStuffA(); } private void ProcessStuffA() { // do tricky A stuff } private static void ProcessStuffB(DelEx me) { me.ProcessStuffB(); } private void ProcessStuffB() { // do tricky B stuff } private readonly static List<ProcessStuffDelegate> ListOfProcessing = new List<ProcessStuffDelegate>() { ProcessStuffA, ProcessStuffB // ProcessStuffC etc }; public DelEx() { foreach (ProcessStuffDelegate processStuffDelegate in ListOfProcessing) { processStuffDelegate(this); } } } 

Using static methods to access their instance methods may be appropriate for those who need only a few delegate methods.

+1
source

All Articles