I get an InvalidOperation Exception when calling MethodInfo.Invoke on my Method, its because it has generic Arguments. After hours of searching in Internet I don't know how to solve this problem. Here is the MethodInfo:
object value = null;
if (propertyType.IsClass)
{
Type primaryKeyType = propertyType.GetPrimaryKeyType();
object primaryKeyValue = property.Value.ToValue(primaryKeyType);
MethodInfo GetEntityMethodInfo = typeof(ReportSettingsExtensions)
.GetMethod("GetEntity", BindingFlags.Static | BindingFlags.InvokeMethod | BindingFlags.NonPublic);
object entity = propertyType;
GetEntityMethodInfo.Invoke(entity, new object[] { primaryKeyValue });
value = entity.GetPrimaryKey();
}
And here is the method:
private static T GetEntity<T>(object primaryKeyValue)
{
T entity = default(T);
new Storage(storage =>
{
entity = storage.Create<T>();
entity.SetPrimaryKey(primaryKeyValue);
storage.Load(entity);
});
return entity;
}
You need to provide or "close" the generic method parameter T, using MethodInfo.MakeGenericMethod ( MSDN )
Something like this:
MethodInfo getEntity =
GetEntityMethodInfo.MakeGenericMethod( ... whatever T should be ... );
var entity = getEntity.Invoke( null, new object[] { primaryKeyValue } );
You should pass null as the first parameter to Invoke because the method is static and so doesn't have an object reference.
Related
Yeah so I set up a little TestClass to figure out what GetMethod would work to actually find the method Test(ref int i). But so far nothing worked.
[Button(nameof(Method))]
public bool whatever;
private void Test(ref int i)
{
Debug.Log("Works");
}
private void Method()
{
Type[] types = { typeof(int) };
MethodInfo methodInfo = GetType().GetMethod(nameof(Test),
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static,
null, types, null);
Debug.Log(methodInfo);
}
What am I supposed to do? I couldn't find anything on the web so far (for GetMethod specifically)
If you mix Eser + gcores you obtain:
private void Test(ref int i)
{
Console.WriteLine(i);
i++;
}
private void Test2(out int i)
{
i = 1000;
}
public void Method()
{
Type[] types = { typeof(int).MakeByRefType() };
MethodInfo methodInfo = GetType().GetMethod(nameof(Test), BindingFlags.NonPublic | BindingFlags.Instance, null, types, null);
int num = 10;
var pars = new object[] { num };
methodInfo.Invoke(this, pars);
Console.WriteLine(pars[0]);
MethodInfo methodInfo2 = GetType().GetMethod(nameof(Test2), BindingFlags.NonPublic | BindingFlags.Instance, null, types, null);
var pars2 = new object[1];
methodInfo2.Invoke(this, pars2);
Console.WriteLine(pars2[0]);
}
Note the typeof(int).MakeByRefType(), and the fact that the object[] array containing the parameters is modified by the invoked method. I've added a second example with out that shows that you still use .MakeByRefType(), only you don't need to initialize the object[] array with a parameter. Ah and you should use the exact BindingFlags you need, not throw every BindingFlags contained in MSDN together. Static and non-static work differently :-)
You can find the method with specified arguments' types by calling an appropriate overload of GetMethod. To make the parameter a reference type use the code:
Type[] types = { typeof(int).MakeByRefType() };
I have the following function. I would like to call and convert a string to int32. How to do I call this function?
static Func GetConverter(T example)
static Func<string, T> GetConverter<T>(T example)
{
return (x) => Convert<T>(x);
}
This is the code used for converting. I got this code from StackOverflow but not sure how to use.
static T Convert<T>(string val)
{
Type destiny = typeof(T);
// See if we can cast
try
{
return (T)(object)val;
}
catch { }
// See if we can parse
try
{
return (T)destiny.InvokeMember("Parse", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Public, null, null, new object[] { val });
}
catch { }
// See if we can convert
try
{
Type convertType = typeof(Convert);
return (T)convertType.InvokeMember("To" + destiny.Name, System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.Public, null, null, new object[] { val });
}
catch { }
// Give up
return default(T);
}
If you must to use GetConverter method, you should first call it to get converter function.
Assuming GetConverter is under class named A:
int value = 0;
var converter = A.GetConverter(value);
then you can call the converter from GetConverter method like a local function:
value = converter("123");
I think you don't have to pass a parameter to GetConverter function. This implementation is better since you dont use example parameter:
static Func<string, T> GetConverter<T>()
{
return (x) => Convert<T>(x);
}
So now you can use it like:
var converter = A.GetConverter<int>();
int value = converter("123");
PS: You can use int.TryParse method instead if you know the target (int) and source (string) types. Or you can use the converter function itself without getting another function to wrap it, like: Convert< int >("123")
I want to call the functions by their name at run time like
string srFunctionName="MyFunction";
So with using this variable i want to call function named as "MyFunction". How can i do that ?
You could use Reflection:
string strFunctionName = "MyFunction";
// get the type containing the method
Type t = Type.GetType("Foo.Bar.SomeTypeContainingYourFunction");
// you will need an instance of the type if the method you are
// trying to invoke is not static. If it is static you could leave that null
object instance = Activator.CreateInstance(t);
// the arguments that your method expects
new object[] arguments = new object[] { 1, "foo", false };
// invoke the method
object result = t.InvokeMember(
strFunctionName,
BindingFlags.InvokeMethod,
null,
instance,
arguments
);
UPDATE:
As requested in the comments section here's a full example with real functions:
using System;
using System.Reflection;
namespace Foo.Bar
{
public class SomeTypeContainingYourFunction
{
public string MyFunction(int foo, string bar, bool baz)
{
return string.Format("foo: {0}, bar: {1}, baz: {2}", foo, bar, baz);
}
}
}
namespace Bazinga
{
class Program
{
static void Main()
{
var strFunctionName = "MyFunction";
var t = Type.GetType("Foo.Bar.SomeTypeContainingYourFunction");
var instance = Activator.CreateInstance(t);
var arguments = new object[] { 1, "foo", false };
var result = t.InvokeMember(
strFunctionName,
BindingFlags.InvokeMethod,
null,
instance,
arguments
);
Console.WriteLine(result);
}
}
}
Here is an example to close the a form
object instance = form;
Type myType = form.GetType();
myType.InvokeMember("Close", BindingFlags.InvokeMethod, null, instance, null);
You can use reflection to create an object of a class and then call a function using that object.
object Instance = Activator.CreateInstance(t); // t is type
MethodInfo mi = t.GetMethod(srFunctionName);
if (mi != null)
mi.Invoke(Instance, args);
else
logError();
I've been trying to execute generic methods and using recursion. The problem is that the method GetMethod returns null. How can I improve the code?
public static T GetElementObject<T>(this XElement element)
{
T returnObject = Activator.CreateInstance<T>();
PropertyInfo[] propertyInfos = returnObject.GetType().GetProperties();
Type propertyType;
foreach (PropertyInfo propertyInfo in propertyInfos)
{
propertyType = propertyInfo.PropertyType;
if (propertyType.IsAssignableFrom(typeof(BaseProxyEntity)))
{
MethodInfo getElementObject = typeof(Utility).GetMethod("GetElementObject<>", System.Reflection.BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(propertyType);
propertyInfo.SetValue(returnObject, getElementObject.Invoke(null, new object[] { element.Descendants(propertyInfo.Name) }), null);
}
else if (propertyType.IsValueType == true)
{
MethodInfo CastValue = typeof(Utility).GetMethod("CastValue<>", System.Reflection.BindingFlags.Static | BindingFlags.Public).MakeGenericMethod(propertyType);
propertyInfo.SetValue(returnObject, CastValue.Invoke(null, new object[] { element.Attribute(propertyInfo.Name).Value }), null);
}
//Other else conditions ...
}
return returnObject;
}
While Eugen Rieck is correct that names are mangled for generic types, they are not mangled for generic methods. Try without the angle brackets: GetMethod("GetElementObject", ... and GetMethod("CastValue",
GetMethod("GetElementObject<>", ...)
Will allways return null, as there is no such method. Names are mangled for generic types, start with listing all methods and proceed from there.
I'm trying to construct a DynamicObject that is able to handle generic method invocations, but it seems that the needed API - although present in RC versions of 4.0 Framework - has been marked internal in RTM (namely, CSharpInvokeMemberBinder is now internal). Is there an equivalent for this code that would work in 4.0 RTM?
public class TransparentObject<T> : DynamicObject {
private readonly T target;
public TransparentObject(T target) {
this.target = target;
}
public override bool TryInvokeMember(
InvokeMemberBinder binder, object[] args, out object result) {
var csBinder = binder as CSharpInvokeMemberBinder;
var method = typeof(T).GetMethod(binder.Name, BindingFlags.Public
| BindingFlags.NonPublic | BindingFlags.Instance);
if (method == null)
throw new MissingMemberException(string.Format(
"Method '{0}' not found for type '{1}'", binder.Name, typeof(T)));
if (csBinder.TypeArguments.Count > 0)
method = method.MakeGenericMethod(csBinder.TypeArguments.ToArray());
result = method.Invoke(target, args);
return true;
}
}
(Code taken from http://bugsquash.blogspot.com/2009/05/testing-private-methods-with-c-40.html )
I am aware that I can use reflection to get generic type parameters here, but I'm looking for a nicer solution - if there is one.
The fastest equivalent I can guess:
private static readonly Func<InvokeMemberBinder, IList<Type>> GetTypeArguments;
static TransparentObject()
{
var type = typeof(RuntimeBinderException).Assembly.GetTypes().Where(x => x.FullName == "Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder").Single();
var dynamicMethod = new DynamicMethod("#", typeof(IList<Type>), new[] { typeof(InvokeMemberBinder) }, true);
var il = dynamicMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, type);
il.Emit(OpCodes.Call, type.GetProperty("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder.TypeArguments", BindingFlags.Instance | BindingFlags.NonPublic).GetGetMethod(true));
il.Emit(OpCodes.Ret);
GetTypeArguments = (Func<InvokeMemberBinder, IList<Type>>)dynamicMethod.CreateDelegate(typeof(Func<InvokeMemberBinder, IList<Type>>));
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
var method = typeof(T).GetMethod(binder.Name, BindingFlags.Public| BindingFlags.NonPublic | BindingFlags.Instance);
if (method == null) throw new MissingMemberException(string.Format("Method '{0}' not found for type '{1}'", binder.Name, typeof(T)));
var typeArguments = GetTypeArguments(binder);
if (typeArguments.Count > 0) method = method.MakeGenericMethod(typeArguments.ToArray());
result = method.Invoke(target, args);
return true;
}