Mostly it comes handy that C# delegates already store the object together with the member function. But is there a way, to store -- and pass as parameters -- only the member function itself, just as the good old pointer-to-member-function in C++?
In case the description is less than clear, I give a self-contained example. And, yes, in the example the insistence to pass around member functions is totally pointless, but I have more serious uses for this.
class Foo {
public int i { get; set; }
/* Can this be done?
public static int Apply (Foo obj, ???? method, int j) {
return obj.method (j);
}
*/
public static int ApplyHack (Foo obj, Func<int, int> method, int j) {
return (int) method.Method.Invoke (obj, new object [] { j });
}
public static readonly Foo _ = new Foo (); // dummy object for ApplyHack
public int Multiply (int j) {
return i * j;
}
public int Add (int j) {
return i + j;
}
}
class Program {
static void Main (string [] args) {
var foo = new Foo { i = 7 };
Console.Write ("{0}\n", Foo.ApplyHack (foo, Foo._.Multiply, 5));
Console.Write ("{0}\n", Foo.ApplyHack (foo, Foo._.Add, 5));
Console.ReadKey ();
}
}
You see, the only workaround I've found is rather ugly and probably slow.
What you want is something called an open instance delegate. I've written about them on my blog
Basically, you can create a delegate to an instance method without tying it to a particular instance, and specify the instance to use it on when you call it:
class Foo {
public int i { get; set; }
public int Multiply (int j) {
return i * j;
}
public int Add (int j) {
return i + j;
}
}
class Program {
static void Main (string [] args) {
Func<Foo, int, int> multiply = (Func<Foo, int, int>)Delegate.CreateDelegate(typeof(Func<Foo, int, int>), null, typeof(Foo).GetMethod("Multiply");
Func<Foo, int, int> add = (Func<Foo, int, int>)Delegate.CreateDelegate(typeof(Func<Foo, int, int>), null, typeof(Foo).GetMethod("Add");
var foo1 = new Foo { i = 7 };
var foo2 = new Foo { i = 8 };
Console.Write ("{0}\n", multiply(foo1, 5));
Console.Write ("{0}\n", add(foo1, 5));
Console.Write ("{0}\n", multiply(foo2, 5));
Console.Write ("{0}\n", add(foo2, 5));
Console.ReadKey ();
}
}
Taking your existing code:
public static int ApplyHack (Foo obj, Func<int, int> method, int j) {
return (int) method.Method.Invoke (obj, new object [] { j });
}
You could do something like this:
public static int ApplyHack (Foo obj, Func<int, int> method, int j) {
var func = (Func<int,int>)Delegate.CreateDelegate(typeof(Func<int,int>), obj, method.Method);
return func(j);
}
This will create a new delegate around the method and the new object. To take your first example:
public static int Apply (Foo obj, ???? method, int j) {
return obj.method (j);
}
The type you are looking for is System.Reflection.MethodInfo
and it would look like this:
public static int Apply (Foo obj, MethodInfo method, int j) {
var func = (Func<int,int>)Delegate.CreateDelegate(typeof(Func<int,int>), obj, method);
return func(i);
}
Note that while you are allocating delegates for each invocation, I believe this will still be faster than using reflection, since you do not have to box function input/output, nor store it in object[]
arrays.
Assuming you're using C# 2.0 or above, and have access to anonymous delegates, you can do it very simply by wrapping the function in an anonymous delegate at the point of storage:
class Foo
{
public Foo(int v)
{
this.v = v;
}
int v;
public int Multiply(int x)
{
return v * x;
}
public int Add(int x)
{
return v+x;
}
delegate int NewFunctionPointer(Foo, int);
delegate int OldDelegateStyle(int);
static void Example()
{
Foo f = new Foo(2);
Foo f2 = new Foo(3);
// instead of this, which binds an instance
OldDelegateStyle oldMul = f.Multiply;
// You have to use this
NewFunctionPointer mul = delegate(Foo f, int x) { return f.Multiply(x); }
NewFunctionPointer add = delegate(Foo f, int x) { return f.Add(x); }
// But can now do this
mul(f, 4); // = 8
add(f2, 1); // = 3
}
}
If you're okay with passing the this
reference as a parameter, why not just use static methods?
class Foo {
public int i;
public static int ApplyHack(Foo foo, Func<Foo, int, int> method, int j) {
return method(foo, j);
}
public static int Multiply(Foo foo, int j) {
return foo.i * j;
}
}
Console.Write("{0}\n", Foo.ApplyHack(foo, Foo.Multiply, 5));
This mainly affects how you construct the Foo
object, without changing how you use it. It also doesn't prevent you from having a non-static int Multiply(int)
method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With