Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Build a static delegate from non-static method

I need to create a delegate to a non-static method of a class. The complications is that at the time of creation I don't have an intance to the class, only its class definition. At call time I do have the instance at hand. Thus I need a way to:

  1. Build an "incomplete" delegat to member method, lacking the instance.
  2. Call the delegate from 1 explicitely passing an intance of the class.

Are both of those possible? How? Note: I'm willing to pay a high perfomance price for number one, but ideally 2 should not be a lot more expensive than a delegate call.

like image 673
David Reis Avatar asked Dec 08 '22 01:12

David Reis


2 Answers

You can use Delegate.CreateDelegate to dynamically construct a delegate for a particular target instance given a MethodInfo. You can look up the MethodInfo with Type.GetMethod (Reflection) and cache it for later use creating the delegate.

For example, this would grab 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 overload of the method, but there are additional GetMethod parameters you can use to disambiguate, if necessary.

like image 185
Dan Bryant Avatar answered Dec 09 '22 14:12

Dan Bryant


What's wrong with just passing an instance in like this?

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

// Invocation.
bar(new Foo());

It does all you need it to: it encapsulates the logic you want to pass around, and can be invoked on an arbitrary class instance.

Edit: If you're restricted to using a delegate of a certain signature (not allowing an instance to be passed explicitly as a parameter), then you could use some form of "instance provider" which is specified at the time of the delegate's creation, but can be mutated later to provide the appropriate instance when it becomes available, e.g.:

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 convoluted, and requires an additional object to be passed around, so perhaps it's not ideal!

like image 28
Will Vousden Avatar answered Dec 09 '22 15:12

Will Vousden