I am using reflection class to invoke some methods which are on the some other dll.
And one of the methods' parameters are type of delegate.
And I want to invoke this methods by using reflection.
So I need to pass function parameters as object array, but I could not find anything about
how to convert delegate to object.
Thanks in advance
A delegate is an object. Just create the expected delegate as you would normally, and pass it in the parameters array. Here is a rather contrived example:
class Mathematician {
public delegate int MathMethod(int a, int b);
public int DoMaths(int a, int b, MathMethod mathMethod) {
return mathMethod(a, b);
}
}
[Test]
public void Test() {
var math = new Mathematician();
Mathematician.MathMethod addition = (a, b) => a + b;
var method = typeof(Mathematician).GetMethod("DoMaths");
var result = method.Invoke(math, new object[] { 1, 2, addition });
Assert.AreEqual(3, result);
}
Instances of delegates are objects, so this code works (C#3 style) :
Predicate<int> p = (i)=> i >= 42;
Object[] arrayOfObject = new object[] { p };
Hope it helps !
Cédric
Here's an example:
class Program
{
public delegate void TestDel();
public static void ToInvoke(TestDel testDel)
{
testDel();
}
public static void Test()
{
Console.WriteLine("hello world");
}
static void Main(string[] args)
{
TestDel testDel = Program.Test;
typeof(Program).InvokeMember(
"ToInvoke",
BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static,
null,
null,
new object[] { testDel });
}
}
I think this blog post:
C# Reflection - Dealing with Remote Objects
answers your question perfectly.
you can see a delegate as variable type "function". the delegate describes the parameters and return value for a matching function.
delegate void Foo(int a); // here a new delegate obj type Foo has been declared
the above example allows 'Foo' to be used as a data type, the only allowed object that can be matched with a variable of type Foo data type is a method with the same signature so:
void MyFunction(int x);
Foo D = MyFunction; // this is OK
void MyOtherFunction(string x);
Foo D = MyOtherFunction; // will yield an error since not same signature.
Once you have assigned a method to a delegate, you can invoke the method via the delegate:
int n = 1;
D( n ); // or D.Invoke( n );
Related
void foo(int one, int two) {
}
public static void Main(string[] args) {
var bar = new int[] { 1, 2 };
foo(params bar);
}
What's the correct syntax to deconstruct the bar array and pass it as the arguments to the foo method?
In some other languages you can use a splat operator foo(...bar) or an unpack operator foo(*bar).
How can I do it in C#?
There isn't an equivalent function in C#. Each argument has to be passed individually.
There are, of course, work arounds that you likely already know. You could declare an overload for your function that would accept an array and call the original function using the first two inputs. The other alternative that I can think of is to declare the function parameter with the params keyword so that it could receive an array or multiple conma-separated elements when called.
void foo(params int[] numbers)
{ // TODO: Validate numbers length
int one = numbers[0];
int two = numbers[1];
}
public static void Main(string[] args) {
var bar = new int[] { 1, 2 };
// both valid function calls below
foo(bar);
foo(bar[0], bar[1]);
}
You can always use Reflection for such purpose.
Here is example snippet on your example method:
class MainClass
{
void foo(int one, int two)
{
Console.WriteLine(one + two);
}
static void Main()
{
var myInstance = new MainClass();
var bar = new object[] { 1, 2 };
var method = myInstance.GetType().GetMethod(nameof(MainClass.foo), BindingFlags.NonPublic | BindingFlags.Instance)
?? throw new InvalidOperationException($"Method '{nameof(MainClass.foo)}' not found");
method.Invoke(myInstance, bar) ;
}
}
The title is may be not clear enough, but I'll show you a short program in order to make you understand what I want to do:
Class Program
{
private static Obj A = new Obj(...);
private static void Function(AnyMethodOfMyObject() m)
{
object[] result = A.m();
...
}
static void main()
{
double a,b,c = 0;
string d = " ";
Function(MethodX(a,b,c));
Function(MethodY(d,a,b));
...
}
}
The methods will always return the same type which is an object[], but I don't have the same number/type of argument.
Thanks !
You can do this simply with a Func<object[]>:
class Program
{
private static Obj A = new Obj(...);
private static void Function(Func<object[]> m)
{
object[] result = m();
...
}
static void main()
{
double a,b,c = 0;
string d = " ";
Function(() => A.MethodX(a,b,c));
Function(() => A.MethodY(d,a,b));
...
}
}
Func<object[]> is a delegate (broadly, a reference to a method) which does not take any parameters, and which returns an array of objects. While MethodX takes 3 parameters (a,b,c), we can create a new anonymous method without doesn't take any parameters itself, and which just calls MethodX and passes in the values of a, b and c (they're captured at the point that we create this new anonymous method). This is what () => MethodX(a, b, c) does.
If you have different Obj instances and you want to control which one the method is called on, then use a Func<Obj, object[]>. This takes an Obj as a parameter, and returns an object[] as before.
class Program
{
private static Obj A = new Obj(...);
private static void Function(Func<Obj, object[]> m)
{
object[] result = m(A);
...
}
static void main()
{
double a,b,c = 0;
string d = " ";
Function(x => x.MethodX(a,b,c));
Function(x => x.MethodY(d,a,b));
...
}
}
What I have: I have a non-static class containing, among others, two private-static methods: one of them can be passed to another one as a delegate parameter:
public class MyClass
{
...
private static string MyMethodToTest(int a, int b, Func<int, int, int> myDelegate)
{
return "result is " + myDelegate(a, b);
}
private static int MyDelegateMethod(int a, int b)
{
return (a + b);
}
}
What I have to do: I have to test (with unit testing) the private-static method MyMethodToTest with passing to it as the delegate parameter the private-static method MyDelegateMethod.
What I can do: I know how to test a private-static method, but I do not know how to pass to this method another private-static method of the same class as a delegate parameter.
So, if we assume that the MyMethodToTest method has no the third parameter at all, the test method will look like:
using System;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
...
[TestMethod]
public void MyTest()
{
PrivateType privateType = new PrivateType(typeof(MyClass));
Type[] parameterTypes =
{
typeof(int),
typeof(int)
};
object[] parameterValues =
{
33,
22
};
string result = (string)privateType.InvokeStatic("MyMethodToTest", parameterTypes, parameterValues);
Assert.IsTrue(result == "result is 55");
}
My question: How to test a private-static method passing to it as a delegate parameter another private-static method of the same class?
Here is how it should go
[TestMethod]
public void MyTest()
{
PrivateType privateType = new PrivateType(typeof(MyClass));
var myPrivateDelegateMethod = typeof(MyClass).GetMethod("MyDelegateMethod", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
var dele = myPrivateDelegateMethod.CreateDelegate(typeof(Func<int, int, int>));
object[] parameterValues =
{
33,22,dele
};
string result = (string)privateType.InvokeStatic("MyMethodToTest", parameterValues);
Assert.IsTrue(result == "result is 55");
}
I wonder if there is a possibility to make the "dynamic" type for variables work for anonymous delegates.
I've tried the following:
dynamic v = delegate() {
};
But then I got the following error message:
Cannot convert anonymous method to type 'dynamic' because it is not a delegate type
Unfortunately, also the following code doesn't work:
Delegate v = delegate() {
};
object v2 = delegate() {
};
What can I do if I want to make a Method that accepts any type of Delegate, even inline declared ones?
For example:
class X{
public void Y(dynamic d){
}
static void Main(){
Y(delegate(){});
Y(delegate(string x){});
}
}
This works, but it looks a little odd. You can give it any delegate, it will run it and also return a value.
You also need to specify the anonymous method signature at some point in order for the compiler to make any sense of it, hence the need to specify Action<T> or Func<T> or whatever.
Why can't an anonymous method be assigned to var?
static void Main(string[] args)
{
Action d = () => Console.WriteLine("Hi");
Execute(d); // Prints "Hi"
Action<string> d2 = (s) => Console.WriteLine(s);
Execute(d2, "Lo"); // Prints "Lo"
Func<string, string> d3 = (s) =>
{
Console.WriteLine(s);
return "Done";
};
var result = (string)Execute(d3, "Spaghettio"); // Prints "Spaghettio"
Console.WriteLine(result); // Prints "Done"
Console.Read();
}
static object Execute(Delegate d, params object[] args)
{
return d.DynamicInvoke(args);
}
If you declare a type for each of your delegates, it works.
// Declare it somewhere
delegate void DelegateType(string s);
// The cast is required to make the code compile
Test((DelegateType)((string s) => { MessageBox.Show(s); }));
public static void Test(dynamic dynDelegate)
{
dynDelegate("hello");
}
Action _;
dynamic test = (_ = () => Console.WriteLine("Test"));
test() // Test
I suppose in some ways either (or both) Delegate or MethodInfo qualify for this title. However, neither provide the syntactic niceness that I'm looking for. So, in short, Is there some way that I can write the following:
FunctionPointer foo = // whatever, create the function pointer using mechanisms
foo();
I can't use a solid delegate (ie, using the delegate keyword to declare a delegate type) because there is no way of knowing till runtime the exact parameter list. For reference, here's what I've been toying with in LINQPad currently, where B will be (mostly) user generated code, and so will Main, and hence for nicety to my users, I'm trying to remove the .Call:
void Main()
{
A foo = new B();
foo["SomeFuntion"].Call();
}
// Define other methods and classes here
interface IFunction {
void Call();
void Call(params object[] parameters);
}
class A {
private class Function : IFunction {
private MethodInfo _mi;
private A _this;
public Function(A #this, MethodInfo mi) {
_mi = mi;
_this = #this;
}
public void Call() { Call(null); }
public void Call(params object[] parameters) {
_mi.Invoke(_this, parameters);
}
}
Dictionary<string, MethodInfo> functions = new Dictionary<string, MethodInfo>();
public A() {
List<MethodInfo> ml = new List<MethodInfo>(this.GetType().GetMethods());
foreach (MethodInfo mi in typeof(Object).GetMethods())
{
for (int i = 0; i < ml.Count; i++)
{
if (ml[i].Name == mi.Name)
ml.RemoveAt(i);
}
}
foreach (MethodInfo mi in ml)
{
functions[mi.Name] = mi;
}
}
public IFunction this[string function] {
get {
if (!functions.ContainsKey(function))
throw new ArgumentException();
return new Function(this, functions[function]);
}
}
}
sealed class B : A {
public void SomeFuntion() {
Console.WriteLine("SomeFunction called.");
}
}
You say you want to keep the number and type of parameters open, but you can do that with a delgate:
public delegate object DynamicFunc(params object[] parameters);
This is exactly the same thing you currently have. Try this:
class Program
{
static void Main(string[] args)
{
DynamicFunc f = par =>
{
foreach (var p in par)
Console.WriteLine(p);
return null;
};
f(1, 4, "Hi");
}
}
You can think of an instance-method delegate as very similar to your Function class: an object an a MethodInfo. So there's no need to rewrite it.
Also function pointers in C and C++ are not any closer to what you need: they cannot be bound to an object instance and function, and also they are statically typed, not dynamically typed.
If you want to "wrap" any other method in a DynamicFunc delegate, try this:
public static DynamicFunc MakeDynamicFunc(object target, MethodInfo method)
{
return par => method.Invoke(target, par);
}
public static void Foo(string s, int n)
{
Console.WriteLine(s);
Console.WriteLine(n);
}
and then:
DynamicFunc f2 = MakeDynamicFunc(null, typeof(Program).GetMethod("Foo"));
f2("test", 100);
Note that I'm using a static method Foo so I pass null for the instance, but if it was an instance method, I'd be passing the object to bind to. Program happens to be the class my static methods are defined in.
Of course, if you pass the wrong argument types then you get errors at runtime. I'd probably look for a way to design your program so that as much type information is captured at compile time as possible.
Here's another bit of code you could use; Reflection is rather slow, so if you expect your Dynamic function calls to be called frequently, you don't want method.Invoke inside the delegate:
public delegate void DynamicAction(params object[] parameters);
static class DynamicActionBuilder
{
public static void PerformAction0(Action a, object[] pars) { a(); }
public static void PerformAction1<T1>(Action<T1> a, object[] p) {
a((T1)p[0]);
}
public static void PerformAction2<T1, T2>(Action<T1, T2> a, object[] p) {
a((T1)p[0], (T2)p[1]);
}
//etc...
public static DynamicAction MakeAction(object target, MethodInfo mi) {
Type[] typeArgs =
mi.GetParameters().Select(pi => pi.ParameterType).ToArray();
string perfActName = "PerformAction" + typeArgs.Length;
MethodInfo performAction =
typeof(DynamicActionBuilder).GetMethod(perfActName);
if (typeArgs.Length != 0)
performAction = performAction.MakeGenericMethod(typeArgs);
Type actionType = performAction.GetParameters()[0].ParameterType;
Delegate action = Delegate.CreateDelegate(actionType, target, mi);
return (DynamicAction)Delegate.CreateDelegate(
typeof(DynamicAction), action, performAction);
}
}
And you could use it like this:
static class TestDab
{
public static void PrintTwo(int a, int b) {
Console.WriteLine("{0} {1}", a, b);
Trace.WriteLine(string.Format("{0} {1}", a, b));//for immediate window.
}
public static void PrintHelloWorld() {
Console.WriteLine("Hello World!");
Trace.WriteLine("Hello World!");//for immediate window.
}
public static void TestIt() {
var dynFunc = DynamicActionBuilder.MakeAction(null,
typeof(TestDab).GetMethod("PrintTwo"));
dynFunc(3, 4);
var dynFunc2 = DynamicActionBuilder.MakeAction(null,
typeof(TestDab).GetMethod("PrintHelloWorld"));
dynFunc2("extraneous","params","allowed"); //you may want to check this.
}
}
This will be quite a bit faster; each dynamic call will involve 1 typecheck per param, 2 delegate calls, and one array construction due to the params-style passing.