How can I create a delegate closure with a mirrored type

How to create a closure that uses an argument of the reflected type? Targeting .net 3.5

Without reflection, I would have

void Main() { int i = 0; Action<Foo> doSomething = (foo) => i += foo.GetNumber(); var myFoo = new Foo(); myFoo.UseFoo(doSomething); Console.WriteLine(i); } class Foo { public int GetNumber() { return 4; } public void UseFoo(Action<Foo> doSomething) { doSomething(this); } } 

When Foo is a type obtained by reflection from another assembly, how would I set doSomething ?

 void Main() { Type fooType = GetType("Foo"); int i = 0; object doSomething = // ???; var myFoo = Activator.CreateInstance(fooType); fooType.GetMethod("UseFoo").Invoke(myFoo, new object[] { doSomething }); Console.WriteLine(i); } 
+4
source share
5 answers

I used both DocXcz and Nikola Anusev answers to get to this.

 static void Main() { var fooType = typeof(Foo); // get type via any method int i = 0; Action<object> doSomething = (foo) => i += (int)foo.GetType().GetMethod("GetNumber").Invoke(foo, null); var typedDoSomething = (typeof(Program)).GetMethod("DelegateHelper").MakeGenericMethod(fooType).Invoke(null, new object[] { doSomething }); var myFoo = Activator.CreateInstance(fooType); fooType.GetMethod("UseFoo").Invoke(myFoo, new object[] { typedDoSomething }); Console.WriteLine(i); } public static Action<T> DelegateHelper<T>(Action<object> generic) { return x => generic(x); } 

Basically I needed to use a common helper method to convert an Action<object> to an Action<T> defined at runtime

+2
source

If you did not statically link this assembly to the Foo class at compile time, you think that you cannot use Foo in your code.

You should use reflection also in closing:

 Action<object> doSomething = (foo) => i+= (int)foo.GetType().GetMethod("GetNumber").Invoke(foo, null); 

This suggests that Foo methos UseFoo is something like this and only works with .NET 4.

 public void UseFoo(Action<Foo> action) { action(this); } 

Of course, you must enclose a full call to UseFoo in a try..catch block, because nothing in the reflection is guaranteed.

Refresh . This only works in .NET 4, where an Action can be passed as an Action adopted by the UseFoo method.

+1
source

I am convinced that it is impossible to do exactly what you want on .NET 3.5.

The only way that comes close is not using lambda, but simple old methods. Essentially, you would define your actions in a class like the following:

 public class FooActionMethods<TFoo> { public static void DoSomething(TFoo foo) { int i = 0; int number = (int)typeof(TFoo).GetMethod("GetNumber").Invoke(foo, null); Console.WriteLine(i + number); } } 

Then you can call, for example, the DoSomething method:

 Type fooType = // somehow, we get the type from other assembly object fooInstance = Activator.CreateInstance(fooType); Type fooActionType = typeof(Action<>).MakeGenericType(fooType); Type fooActionMethodsType = typeof(FooActionMethods<>).MakeGenericType(fooType); Delegate action = Delegate.CreateDelegate(fooActionType, fooActionMethodsType, "DoSomething"); fooType.GetMethod("UseFoo").Invoke(fooInstance, new object[] { action }); 

Since the entire FooActionMethod class is shared, we can use reflection ( MakeGenericType ) and create a private FooActionMethod with the exact type Foo . Since at compile time we do not have information about TFoo , we can only interact with our instances through reflection. To simplify these interactions, check out the SO question , which concerns some libraries that would make it easier to work with reflection.

Other than that, I think you can’t do anything. Thanks for the good question - makes a great puzzle! :)

Just like a side effect, I also tried to solve this using expression trees to dynamically create a lambda expression. I could not find a way to enable closures with expression trees. Otherwise, this method will work fine.

+1
source

A closure in C # is something generated by the compiler. If you need the same code generated for your reflected type, you will have to generate the code manually.

0
source

If foo implements a suitable interface, you can have Action working on that interface.

If not, you need to either use reflection in your deletet (easier) or compile the delegate at runtime using the expression API (more work, maximum performance).

Since the C # compiler creates a closure on i , you need to continue to do this:

 Action<int> incrementI = inc => i += inc; 

Now you can use increment i in the compiled deletion to increase i .

0
source

All Articles