Create generic delegate using reflection - c#

I have the following code:
class Program
{
static void Main(string[] args)
{
new Program().Run();
}
public void Run()
{
// works
Func<IEnumerable<int>> static_delegate = new Func<IEnumerable<int>>(SomeMethod<String>);
MethodInfo mi = this.GetType().GetMethod("SomeMethod").MakeGenericMethod(new Type[] { typeof(String) });
// throws ArgumentException: Error binding to target method
Func<IEnumerable<int>> reflection_delgate = (Func<IEnumerable<int>>)Delegate.CreateDelegate(typeof(Func<IEnumerable<int>>), mi);
}
public IEnumerable<int> SomeMethod<T>()
{
return new int[0];
}
}
Why can't I create a delegate to my generic method? I know I could just use mi.Invoke(this, null), but since I'm going to want to execute SomeMethod potentially several million times, I'd like to be able to create a delegate and cache it as a small optimization.

You method isn't a static method, so you need to use:
Func<IEnumerable<int>> reflection_delgate = (Func<IEnumerable<int>>)Delegate.CreateDelegate(typeof(Func<IEnumerable<int>>), this, mi);
Passing "this" to the second argument will allow the method to be bound to the instance method on the current object...

Related

How to "invoke" PropertyInfo of type Action<,> in runtime

I have a generic class and a property of type Action<,>. I am wondering if there is a way to actually invoke this delegate using reflection in runtime, not just set value to this class property (via PropertyInfo.SetValue).
I tried a lot of things, like using expressions, dummy casting, read forums, but none of the solutions worked for me.
Workaround:
What I could think of is creating a dummy method which internally calls the delegate, and with reflection is fairly easy to invoke this method.
public class Student
{
public string Name { get; set; }
}
public class ConfigData<T>
where T: class
{
public Action<T, object> ValueInjector { get; set; }
public void SetValue(T entity, object valueToSet)
{
this.ValueInjector(entity, valueToSet);
}
}
class Program
{
static void Main(string[] args)
{
var configObj = new ConfigData<Student>()
{
ValueInjector = (x, y) =>
{
// Some custom logic here
x.Name = y.ToString();
}
};
// Parameters
Student student = new Student();
object valueToSet = "Test";
Type configType = configObj.GetType();
PropertyInfo propertyInfo = configType.GetProperty("ValueInjector");
// Invoke the property info somehow with the parameters ?
// Workarround - invoke a dummy method instead
MethodInfo methodInfo = configType.GetMethod("SetValue");
methodInfo.Invoke(configObj, new object[] { student, valueToSet });
Console.WriteLine(student.Name);
}
}
I want to be able to invoke the propertyInfo variable and pass to it the two parameters I already have (student, valueToSet), since I know that it represent a delegate which can be run.
Update:
I tried with castings as suggested by #HimBromBeere.
//Error in runtime
var del = (Action)propertyInfo.GetValue(configObj, null);
//Error in runtime
var del = (Action<object, object>)propertyInfo.GetValue(configObj, null);
// Works but no generic
var del = (Action<Student, object>)propertyInfo.GetValue(configObj, null);
del.Invoke(student, valueToSet);
Only the last casting works and I am able to call Invoke on the delegate (no need of DynamicInvoke) and it works. However this is not a solution because I do not know the exact type to cast in runtime. I have it as variable T. Something like:
var del = (Action<T, object>)propertyInfo.GetValue(configObj, null);
So maybe if I manage to make a generic Type like this:
var d1 = typeof(Action<,>);
Type[] typeArgs = { propertyInfo.DeclaringType.GenericTypeArguments[0], typeof(object) };
Type delegateType = d1.MakeGenericType(typeArgs);
there might be a way to do this conversion and execute. Still wondering.
You can cast the value returned from the property back to a delegate, e.g:
var del = (Action)propertyInfo.GetValue(configObj, null);
Now call the delegate with your params:
del.DynamicInvoke(student, valueToset)

C# pass methods as parameters

I'm working with an C API in C#. In C Methods are passed as parameters and I'm trying to accomplish the same thing in C#.
in C I would call the functions the following way:
LL_SetStatusCb(OnStatusRcv);
LL_SetScanCb(scanCb);
LL_Scan();
Note that the used methods are defined in the following way:
void OnStatusRcv(ll_status_t status)
void scanCb(ll_scan_result_t *result)
In C# the methods are defined in the same way but I don't know how I can pass those methods.
C# equivalent of function pointers are delegates. You can use Func and Action to pass methods as parameters. Func delegate represents method which takes N arguments and returns value, Action delegate represents void method.
Consider this
void (* myFunction)(int parameter)
in C# would be
Action<int>
Please try this code:
create ll_scan_result_t and ll_status_t classes.
class Program
{
delegate void ActionRef<T>(ref T item);
static void Main(string[] args)
{
ll_status_t _status = new ll_status_t();
LL_SetStatusCb(_status, OnStatusRcv);
ll_scan_result_t _scan = new ll_scan_result_t();
LL_SetScanCb(ref _scan);
}
static void LL_SetScanCb(ref ll_scan_result_t status, ActionRef<ll_scan_result_t> getCachedValue)
{
//... do something
}
static void LL_SetStatusCb(ll_status_t result, Action<ll_status_t> getCachedValue)
{
//... do something
}
static void OnStatusRcv(ref ll_scan_result_t sresult)
{
//... do something
}
static void scanCb(ll_status_t s)
{
//... do something
}
}
Use the Func Delegate like below
public class myClass
{
public bool TestMethod(string input)
{
return true;
}
public bool Method1(Func<string, bool> methodName)
{
return true;
}
public void newMthod()
{
Method1(TestMethod);
}
}
In C#, the equivalent to C/C++ function pointers are delegates. A delegate is a type that represents references to methods with a particular parameter list and return type. When you instantiate a delegate, you can associate its instance with any method that has a compatible signature and return type. You can call the method through the delegate instance.
Here's an example. First, declare a delegate:
public delegate void Del(string message);
Now, Del is a delegate type which can be used to call to any method that returns void and accepts an argument of type string. Now, let's create some method matching the signature and return type of Del:
public static void DelegateMethod(string message)
{
Console.WriteLine(message);
}
Now, let's create an instance of Del and associate it with DelegateMethod, like this:
Del handler = DelegateMethod;
If you want to call DelegateMethod, you can do it by:
handler("Hello World");
Notice that since Del is a type, you can do something like this:
public static void SomeMethod(Del callback, string callbackParams)
{
callback(callbackParams);
}
Which can be used as:
SomeMethod(handler, "Hello World");
With that said, there are othes ways of working with delegates. You can use Func and Action delegates. Func is a delegate that points to a method that accepts one or more arguments and returns a value, that is, it doesn't return void. Action is a delegate that points to a method which in turn accepts one or more arguments but returns no value (returns void). In other words, you should use Action when your delegate points to a method that returns void.
Here's an example of using an Action delegate:
static void Main(string[] args)
{
Action<string> action = new Action<string>(Display);
action("Hello!!!");
Console.Read(); //Prevents from closing the command line right away.
}
static void Display(string message)
{
Console.WriteLine(message);
}
Therefore, something like
void (* funcPtr)(int) = &someFuncWithAnIntArg;
(*funcPtr)(10);
Is equivalent in C# to
Action<int> funcPtr = new Action<int>(someFuncWithAnIntArg);
funcPtr(10);
And now for a Func delegate:
static void Main(string[] args)
{
Func<int, double> func = new Func<int, double>(CalculateHra);
Console.WriteLine(func(50000));
Console.Read();
}
static double CalculateHra(int basic)
{
return (double)(basic * .4);
}
The syntax for a Func delegate accepting an argument and returning a value is like this Func<TArgument, TOutput> where TArgument is the type of the argument and TOutput is the type of returned value. There are many more types of Func (browse the left tree index) and Action (also browse the left tree index) delegates.
And last, but not least, we have the Predicate delegates which is typically used to search items in a collection or a set of data. Let's define some boilerplate code to explain:
class Customer
{
public int Id { get; set; }
public string FirstName { get; set; }
}
Then, let's try it in:
static void Main(string[] args)
{
List<Customer> customers = new List<Customer>();
customers.Add(new Customer { Id = 1, FirstName = "Stack" });
customers.Add(new Customer { Id = 2, FirstName = "Overflow" });
Predicate<Customer> pred = x => x.Id == 1;
Customer customer = customers.Find(pred);
Console.WriteLine(customer.FirstName);
Console.Read();
}
The last code snippet will print "Stack". What happened is that the Predicate delegate named prep was used as a search criteria to search in the list customers. Basically, this delegate was run on every element x of the list, and when x.Id == 1 it returns true, false otherwise. The x element where the predicate returned true is returned as the result of the Find method.

Call generic method by type

I have these classes:
public static class A{
...
public C Run<T>(string something)
{
...
}
}
public static class B{
...
public void Exec<T>(Type type)
{
MethodInfo method = typeof(A).GetMethod("Run");
MethodInfo generic = method.MakeGenericMethod(type);
var result = generic.Invoke(null, new object[] { "just a string" });
// bad call in next line
result.DoSomething();
}
}
public class C{
...
public void DoSomething(){}
}
How to convert result to type for call DoSomething method? And how simpler to call generic method using type variable?
How to convert result to type for call DoSomething method?
You cannot do that statically, because your code does not know the type at compile time, and the object is already of the correct type. One way to do it in .NET 4.0 and later is to use dynamic instead of object for the result, like this:
dynamic result = generic.Invoke(null, new object[] { "just a string" });
result.DoSomething(); // This will compile
You can do it like this only if you are 100% certain that the DoSomething() method is going to be there at runtime. Otherwise, there is going to be an exception at runtime, which you would need to catch and process.

Get all Target instances for a delegate

If I only register one method of one class to a delegate, I can use the delegate.Target, but when I subscripe more methods from different classes this does not work anymore. Is there another way to access the subscribers list of this delegate?
Here is the code: The foreach loop is being evaluated to null at runtime (it compiles)
public delegate void WriteMessage(string msg);
internal class Program
{
private static void Main(string[] args)
{
var myClass = new MyClass();
var writer = new WriteMessage(myClass.WriteMessage);
writer += SaySomething; //method in this class
writer += myClass.SayShit; //instance class
writer += AnotherClass.Say; //static class
foreach(string target in (string[])writer.Target)
{
Console.WriteLine(target);
}
Console.ReadLine();
}
private static void SaySomething(string msg)
{
Console.WriteLine("HI!!!!");
}
}
complete code:
http://pastebin.com/AzzRGMY9
Delegate[] list = delegate.GetInvocationList();
That will get you an array of Delegate objects, which you can use to get the list of Targets.
This is just additional information from the accepted answer, as I am looking the same information online.
If you want to invoke all registered methods upon receiving all the invocation list, you can use this code:
Delegate[] listAllRegisteredMethods = writer.GetInvocationList(); //writer is the variable based on the question example
foreach(Delegate c in listAllRegisteredMethods )
{
object[] p = { }; //Insert your parameters here inside the array if your delegate has parameters
c.DynamicInvoke(p); //Invoke it, if you have return values, assign it on a different variable
}

Setting a generic type parameter from a method parameter

Is there any way to do something like this?
void SomeMethod(Type generic)
{
SomeGenericMethod<generic>();
}
I need to pass the type in as a "normal" parameter and not a generic type parameter.
You can do it with reflection:
public class foo
{
public void SomeMethod(Type type)
{
var methodInfo = this.GetType().GetMethod("SomeGenericMethod");
var method = methodInfo.MakeGenericMethod(new[] { type });
method.Invoke(this, null);
}
public void SomeGenericMethod<T>()
{
Debug.WriteLine(typeof(T).FullName);
}
}
class Program
{
static void Main(string[] args)
{
var foo = new foo();
foo.SomeMethod(typeof(string));
foo.SomeMethod(typeof(foo));
}
}
That said, using reflection in this way means you are losing some of the benefits of using generics in the first place, so you might want to look at other design alternatives.
Assuming that your method is defined in a class called MyClass, this should do it:
var MyObject = new MyClass();
typeof(MyClass).GetMethod("SomeGenericMethod").MakeGenericMethod(generic).Invoke(myObject, null);
Type.GetMethod() gets an object which describes a method defined in the Type it's called on.
The method is generic, so we need to call MakeGenericMethod, and pass its one generic parameter.
We then invoke the method, passing the object we want the method called on and any arguments it takes. As it takes no arguments, we just pass null.

Categories