I am loading a dll using loadfrom and iterating thru the methods to find ones that match a signature. When I find it I want to assign it as a delegate so I can call it later. This is what I am doing...
foreach (MethodInfo method in methodInfos)
{
if (method.GetParameters().Length == 2)
{
ParameterInfo[] parameters = method.GetParameters();
if (parameters[0].ParameterType.Name == "Command"
&& parameters[1].ParameterType.Name == "ExposedVariables")
{
aoc.methodinfo = method;
Command.delCmdMethod del = (Command.delCmdMethod)
Delegate.CreateDelegate(typeof(Command.delCmdMethod)
, null
, method);
}
}
}
Problem is - the delegate assignment does not work. I get an error binding to target method.
I read on the web that the the 2nd parameter could be the issue if the method is not static. My method is NOT static.
Any ideas?
Although Miky Dinescu's answer might be helpful, it is only partially correct. There does exist an overload for Delegate.CreateDelegate which will most likely help you.
First off, Miky is right that you have to pass the instance as the second parameter, but this is only the case if you want to create what is called a closed delegate. This means an instance is bound to the delegate along with the method. In practice this means when calling the delegate, it will always operate on the same instance.
From your question, it looks like that isn't what you are trying to achieve. If you want to be able to pass the instance along when calling the delegate, you have to use the CreateDelegate( Type type, MethodInfo method ) overload. This allows you to create what is called an open instance delegate.
Since you'll have to pass the instance along when calling the method, this means there is an extra parameter required in your delegate type. The first parameter of your delegate type will need to correspond to the type of the class in which the method is contained.
Example:
MethodInfo toUpperMethod
= typeof( string ).GetMethod( "ToUpper", new Type[] { } );
Func<string, string> toUpper
= (Func<string, string>)Delegate.CreateDelegate(
typeof( Func<string, string> ), toUpperMethod );
string upper = toUpper( "test" ); // Will result in "TEST".
Since - just like you - I found these overloads to be unclear, I created two helper functions to clearly separate creating a 'normal' delegate or an open instance delegate. This code, along with a more thorough discussion can be found in my blog post.
If the method is not static then you need to pass in a reference to an instance of the class who's method you are going to be invoking using the delegate.
If you don't know which instance you will be using at the time when you are attempting to create the delegate you will need to store the type and method information for later and then create the Delegate after you have the instance of the class.
EDIT
To answer your comment, the object that you need to pass is an object of the type that contains the method your are trying to bind your delegate to. So based on your code sample it's not the Command object but an object of the class from the DLL.
So, let's say that you have this .NET assembly DLL: myassembly.dll. The assembly contains the following class:
namespace MyNamespace
{
public class SomeClass
{
public SomeClass()
{
}
public void Method1(object Command, object ExposedVariables)
{
}
public void Method2(object Command, object ExposedVariables)
{
}
}
You would need to create an instance of the class SomeClass before you could create delegates bound to Method1 or Method2 of that class. So, the code which creates the delegate should look like this:
// assuming that method info is a MethodInfo contains information about the method
// that you want to create the delegate for, create an instance of the class which
// contains the method..
object classInstance = Activator.CreateInstance(methodInfo.DeclaringType);
// and then create the delegate passing in the class instance
Delegate.CreateDelegate(typeof(Command.delCmdMethod), classInstance, methodInfo);
Related
I have some troubles to create the right delegate for this instance method:
public T AddComponent<T>() where T : Component
{
....
}
I am using reflection to get the specific MethodInfo and on Delegate.CreateDelegate I am getting an error binding to target method
private delegate T AddComponent<out T>();
private static AddComponent<Component> AddC { get; set; }
public void Test()
{
var go = new GameObject();
var targetAddComponent =
typeof (GameObject).GetMethods().First(m => m.Name == "AddComponent" && m.GetParameters().Length == 0);
AddC = (AddComponent<Component>) Delegate.CreateDelegate(typeof (AddComponent<Component>), go, targetAddComponent, true);
....
}
Do you have any clues on what I am doing wrong?
The method info is a method info for method GameObject.AddComponent<T>, which returns T. The delegate, which you have incredibly confusingly named the same as the method, must be to a method that returns Component. What have you done to cause T to equal Component? Nothing.
Put another way: the method info is a method info to something that isn't actually a callable method until it is constructed. It's a generic pattern for making methods, not a method. Make it a method if you want to make a delegate to it. You need to supply a type argument for type parameter T in the method.
Here's my attempt at calling an existing generic method with a type argument. 'Strongly typed reflection' may not be a suitable term, but it basically means finding and invoking the reflected method without using a name string.
public class TestClass
{
public static void Test(Type type)
{
InvokeTestMethodWithType(type);
}
private void Test<T>() { ... }
private static void InvokeTestMethodWithType(Type type)
{
// This doesn't compile! - can I find Test<> using this approach?
Expression<Func<TestClass, Action>> ex = x => x.Test<>;
// invoke it
((MethodCallExpression)ex.Body).Method.MakeGenericMethod(type).Invoke(new TestClass(), null);
}
}
Sample call would end up call the private Test().
TestClass.Test(typeof(Foo))
As you can see, I'm struggling with the expression and not entirely sure if it can be executed in this manner.
Do I have to dummy invoke the action in the expression like this post?
x => x.Test<object>()
The trick I use is simple: pass a fake generic type argument:
Expression<Func<TestClass, WhateverTestReturns>> ex = x => x.Test<string>();
// invoke it
((MethodCallExpression)ex.Body)
.Method
.GetGenericMethodDefinition()
.MakeGenericMethod(type)
.Invoke(new TestClass(), null);
The method call expression will then contain a method info for Test<string>(), but you can easily use GetGenericMethodDefinition to remove the generic argument, and then MakeGenericMethod to put a different one back in its place.
You don't even need to use Expression in a case like this - simply cast TestClass.Test<string> to a delegate, and you'll have a Method property that gives you the same method info.
Suppose I have a method
public void Whatever<T>() { ... }
suppose I have a type in the form of a string
var myType = "System.String";
Normally, I'd call the method like:
Whatever<string>();
But I'd like to be able to call it using myType somehow. Is this possible?
I know this doesn't work, but conceptually:
Whatever<Type.GetType(myType)>();
You can use Reflection and MethodInfo.MakeGenericMethod for this
Reflect the method that you want to call to get the MethodInfo, then make it generic and Invoke it.
Something like this (notice that this is from the top of my head (no VS here), it might not be perfect yet but should get you started):
Type type = myObject.GetType();
MethodInfo method = type.GetMethod("NameOfMethod");
MethodInfo genericMethod = method.MakeGenericMethod(typeOf(string));
genericMethod.Invoke(myObject, new object[] { "theString" } );
You can create an instance via Reflection (or provide both generic and non-generic Whatever type). Of course Reflection is slow (and you can have only an object or base class reference). Often the generic type can be just a specialization of the non-generic one.
it may be a duplicate of
How to dynamically call a class' method in .NET?
and of
how to achieve calling a function dynamically, thats right the function to be called is decided from database values, using c#
but the above two have solutions which as the answers said are complicated, not for a beginner i guess.
and
both solutions contain "type" which from the code i think is for defining the class the method belongs to.
like
static void caller(String myclass, String mymethod)
{
// Get a type from the string
Type type = Type.GetType(myclass);
// Create an instance of that type
Object obj = Activator.CreateInstance(type);
// Retrieve the method you are looking for
MethodInfo methodInfo = type.GetMethod(mymethod);
// Invoke the method on the instance we created above
methodInfo.Invoke(obj, null);
}
but my initial web site, only contains one class common to all the functions,
a database which has "function name" "func id"
supposed :- function name exactly same as that in code
i only want to achieve the following
get the string value of function name according to the id mentioned in the text box
now call that function, whose name is in the string variable
problem
the methodinfo, needs the "type.GetMethod(mymethod);"
..
In order to call a function you need to specify the type this function is declared on. If all functions you are going to call are declared on a common class you could do the following:
static void CallFunc(string mymethod)
{
// Get a type from the string
Type type = typeof(TypeThatContainsCommonFunctions);
// Create an instance of that type
object obj = Activator.CreateInstance(type);
// Retrieve the method you are looking for
MethodInfo methodInfo = type.GetMethod(mymethod);
// Invoke the method on the instance we created above
methodInfo.Invoke(obj, null);
}
If the functions you are going to call are static you don't need an instance of the type:
static void CallFunc(string mymethod)
{
// Get a type from the string
Type type = typeof(TypeThatContainsCommonFunctions);
// Retrieve the method you are looking for
MethodInfo methodInfo = type.GetMethod(mymethod);
// Invoke the method on the type
methodInfo.Invoke(null, null);
}
I see 2 solutions:
you need to map function id to
real function name
call
type.GetMethods() to get list of all
methods and choose right one
How does the code looks that would create an object of class:
string myClass = "MyClass";
Of the above type, and then call
string myMethod = "MyMethod";
On that object?
Use Type.GetType(string) to get the type object.
Use Activator.CreateInstance(Type) to create an instance.
Use Type.GetMethod(string) to retrieve a method.
Use MethodBase.Invoke(object, object[]) to invoke the method on the object
Example, but with no error checking:
using System;
using System.Reflection;
namespace Foo
{
class Test
{
static void Main()
{
Type type = Type.GetType("Foo.MyClass");
object instance = Activator.CreateInstance(type);
MethodInfo method = type.GetMethod("MyMethod");
method.Invoke(instance, null);
}
}
class MyClass
{
public void MyMethod()
{
Console.WriteLine("In MyClass.MyMethod");
}
}
}
Each step needs careful checking - you may not find the type, it may not have a parameterless constructor, you may not find the method, you may invoke it with the wrong argument types.
One thing to note: Type.GetType(string) needs the assembly-qualified name of the type unless it's in the currently executing assembly or mscorlib.
I've created a library which simplifies dynamic object creation and invocation using .NET you can download the library and the code in google code: Late Binding Helper
In the project you will find a Wiki page with the usage, or you can also check this article in CodeProject
Using my library, your example will look like this:
IOperationInvoker myClass = BindingFactory.CreateObjectBinding("MyClassAssembly", "MyClass");
myClass.Method("MyMethod").Invoke();
Or even shorter:
BindingFactory.CreateObjectBinding("MyClassAssembly", "MyClass")
.Method("MyMethod")
.Invoke();
It uses a fluent interface, and truly simplifies this kind of operations. I hope you could find it useful.
The following assumes an object with a public constructor and a public method that returns some value but takes no parameters.
var object = Activator.CreateInstance( "MyClass" );
var result = object.GetType().GetMethod( "MyMethod" ).Invoke( object, null );
Assuming that your class is in your executing assembly, your constructor and your method is parameterless.
Type clazz = System.Reflection.Assembly.GetExecutingAssembly().GetType("MyClass");
System.Reflection.ConstructorInfo ci = clazz.GetConstructor(new Type[] { });
object instance = ci.Invoke(null); /* Send parameters instead of null here */
System.Reflection.MethodInfo mi = clazz.GetMethod("MyMethod");
mi.Invoke(instance, null); /* Send parameters instead of null here */