Call a static method of a static class using reflection - c#

i trying to call a static method like this :
Assembly myAssembly = Assembly.LoadFrom(filePath);
Type Mytype = myAssembly.GetType("MyClass");
string returnedValue = Mytype.GetMethod("MyMethod").Invoke(null, null).ToString();
MessageBox.Show(returnedValue);
but i get this error : Object reference not set to an instance of an object.
internal static class MyClass
{
internal static string MyMethod(int param1)
{
return "HI"
}
}
Please help me to resolve this problem, regards.

First of all you need to pass correct BindingFlags so your method can be found:
var methodInfo = typeof(MyClass).GetMethod("MyMethod",
BindingFlags.Static |
BindingFlags.NonPublic);
Then you need to pass correct parameters to the Invoke function:
methodInfo.Invoke(null, new object [] {1})

Related

CreateDelegate Error: System.ArgumentException Cannot bind to the target method

I have an app that takes the dll of an external app, look into it for a specified class and method. It then gets the methodinfo from this external method and tries to then Create a delegate via Delegate.CreateDelegate
I constantly get
System.ArgumentException: 'Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.'
I have gone and extracted the code a bit to make it easier to share and debug as well as write a small simple external app to read from. See the code below:
External App Example as Library (.Net Framework 4.8)
using System;
namespace MethodLib
{
public class PrintText
{
public string Print(string textToPrint, int number)
{
return $"{ PrintPrivate(textToPrint) }: {number}";
}
public static string PrintStatic(string textToPrint)
{
return textToPrint;
}
public void PrintVoid(string textToPrint)
{
Console.WriteLine(textToPrint);
}
private string PrintPrivate(string textToPrint)
{
return $"This is { textToPrint }";
}
}
}
App to CreateDelegate
MethodInfo Creation
using System;
using System.Reflection;
namespace DelegateApp
{
public class PluginSupport
{
public MethodInfo GetMethodInfo(string methodName, string externalLocation)
{
var instance = Activator.CreateInstance(Assembly.LoadFrom(externalLocation)
.GetType("MethodLib.PrintText"));
var methodInfo = instance.GetType()
.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
return methodInfo;
}
}
}
Create Delegate Part
namespace DelegateApp
{
public class MethodGenerator
{
private PluginSupport _pluginSupport;
public MethodGenerator()
{
_pluginSupport = new PluginSupport();
}
public MethodDetails Create(string methodName, string path)
{
var method = _pluginSupport.GetMethodInfo(methodName, path);
if (Equals(method, null))
{
throw new KeyNotFoundException($"Method '{ methodName }' doesn't exist in class");
}
return new MethodDetails
{
MethodName = method.Name,
ComponentName = method.DeclaringType.Name,
FriendlyName = method.DeclaringType.Name,
Parameters = method.GetParameters(),
LogicalPath = method.DeclaringType.Assembly.Location,
Method = (Func<string>)Delegate.CreateDelegate(typeof(Func<string>), method)
};
}
}
}
What have I tried
So reading a lot of different post I gather that the call I am using
(Func<string>)Delegate.CreateDelegate(typeof(Func<string>), method) is actually meant for static methods only, and as I am interested in all the public methods I am missing a target/instance.
So from other examples, you need to create the instance and pass that in as well, so I used the var myInstance = Actovator.CreateInstance and then passed this variable in as well, ending up with the following
(Func<string>)Delegate.CreateDelegate(typeof(Func<string>), myInstance, method)
I have also tried to use this one
public static Delegate CreateDelegate(Type type, Type target, string method, bool ignoreCase);
All of this keeps throwing
System.ArgumentException: 'Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.'
The only time I get it to work, is when I do the following:
methodName = PrintStatic from external app
var methodInfo = instance.GetType()
.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static);
var deleg = (Func<string>)Delegate.CreateDelegate(typeof(Func<string>),null, method)
of course this is not what I want as this only does the static for me and I want the non-static as well. But even with this if I add BindingFlags.Instance to the mix the static will also throw the same error.
If I also remove BindingFlags.Instance and my methodName = Print, then methodInfo is null.
My Questions
What am I not understanding/missing with regards to the Delegate.CreateDelegate?
What code am I missing that this is not working as I am expecting?
Is there a different way to do the same thing?
From creating the Delegate I want to invoke it later in the code, but is there a penalty for just using the invoke directly on methodinfo instead of creating a delegate then invoking it?
Why does methodinfo not give me my public non-static member if BindingFlags.Instance is omitted?
Thanks to #Charlieface, I realised my signature types were not corresponding to me creating the delegate.
So what I finally ended up with in this example code was to do the following in MethodGenerator class
Get the parameters from methodinfo
Go through the params and add them to a list of Types and get the type of each param
Build a func where I do not know the number of types it will need and replace the number with the amount of params I have from methodinfo + output type
Check if method isstatic and based on this set it to
methHead = method.IsStatic
? Delegate.CreateDelegate(delegateFunc.MakeGenericType(types.ToArray()), null, method)
: Delegate.CreateDelegate(delegateFunc.MakeGenericType(types.ToArray()), instance, method);
This is a bit of elaborate code I guess, but it works and will need to refine it or drop it in the actual code base where we want to use it. But as #Charlieface mentioned if you don't know the type, there isn't much point to the delegate.
Final piece of code
public MethodDetails Create(string methodName, string path)
{
var method = _pluginSupport.GetMethodInfo(methodName, path);
if (Equals(method, null))
{
throw new KeyNotFoundException($"Method '{ methodName }' doesn't exist in class");
}
var instance = Activator.CreateInstance(method.DeclaringType);
List<Type> types = new List<Type>();
var methodPrams = method.GetParameters();
foreach (var item in methodPrams)
{
types.Add(Type.GetType(item.ParameterType.UnderlyingSystemType.FullName));
}
var funcType = typeof(Func<>);
var delegateFunc = Type.GetType(funcType.FullName.Replace("1", (methodPrams.Length + 1).ToString()));
Delegate methHead;
types.Add(typeof(string));
methHead = method.IsStatic
? Delegate.CreateDelegate(delegateFunc.MakeGenericType(types.ToArray()), null, method)
: Delegate.CreateDelegate(delegateFunc.MakeGenericType(types.ToArray()), instance, method);
return new MethodDetails
{
MethodName = method.Name,
ComponentName = method.DeclaringType.Name,
FriendlyName = method.DeclaringType.Name,
Parameters = method.GetParameters(),
LogicalPath = method.DeclaringType.Assembly.Location,
Method = methHead
};
}

invoke non static method in c#

I want to invoke a class
"***" is the solution that works for me but I want to invoke
THIS IS THE SOLUTION THAT GIVES ME THE ERROR :
Type t = Type.GetType(svClass);
MethodInfo method = t.GetMethod("execute", BindingFlags.instance| BindingFlags.Public);
Ret = (string)method.Invoke(null, new object[] { context.Request});
public string execute(HttpRequest req)
so that I tried to MethodInfo method = t.GetMethod("execute", BindingFlags.instance | BindingFlags.Public);
but it gives me the error "non-static method requires a target"
*** THIS IS THE WORKING SOLUTION FOR STATIC METHOD
Type t = Type.GetType(svClass);
MethodInfo method = t.GetMethod("execute", BindingFlags.static| BindingFlags.Public);
Ret = (string)method.Invoke(null, new object[] { context.Request});
to invoke
public class XXXXX
{
public static string execute(HttpRequest req){}
}
The secret is to change your binding flags to get a MethodInfo that matches the signature of the method you wish to call.
Eg:
public static string execute(HttpRequest req){}
Will be accessed via
MethodInfo method = t.GetMethod("execute", BindingFlags.static| BindingFlags.Public);
However, to access
public string execute(HttpRequest req){}
you need to do
var classObj = new Class();
MethodInfo method = classObj.GetType().GetMethod("execute", BindingFlags.Instance| BindingFlags.Public);
Instance means that the method is a member of a class object, and not of the class type.
(Instance vs Static)
var parameterArray = new object[]{ YourHttpRequestHere};
var result = method.Invoke(classObj,parameterArray);
So remember, if the method belongs to an instance, then you need to grab the method from that instance type, and then you need to invoke it with a reference to the instance variable (classObj) above.

C# - GetMethod returns null

I have A class:
public abstract class A
{
}
And then I have B class that derives from it:
public sealed class B : A
{
public void SomeMethod()
{
var method = this.GetType().GetMethod("AddText");
}
private void AddText(string text)
{
...
}
}
Why is GetMethod returning null?
var methodInfo = this.GetType().GetMethod("AddText", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(string) }, null);
Your method has a parameter, you need to use the overload that accepts a type array for the parameter types and the binding flags.
In .net Method signatures are based on their name, their return type, and their parameters.
So if your method has parameters you have to tell Reflection what parameter types it has via a Type[].
By default, Reflection will only search for public methods.
You need to pass BindingFlags.Instance | BindingFlags.NonPublic.

How to call a method with struct constraint to unknown struct

Question is simple: I'm using reflection to get a value. Then if it's a struct, I'm calling a method FooStruct, else FooClass:
Type type = x.GetType();
foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
var val = fieldInfo.GetValue(value);
object obj = type.IsValueType ? val.FooStruct() : val.FooClass();
fieldInfo.SetValue(x, obj);
}
problem is that FooStruct has a constraint:
public static T FooStruct<T>(this T value) where T : struct
{
//...
}
so question is: is it possible to call a method with struct constraint for an object which contains a boxed struct instance without reflection?
I'd happily be proven wrong by another answer, but I don't think this is possible without resorting even more to reflection. See further below for the reason that makes me suspect this. See end of the answer for a reflection-based solution.
Practical suggestion: I would simply drop the constraint on your FooStruct and FooClass methods, and additionally:
either make them non-generic and accept an argument of type object (which is what val is declared as, anyway). There's no advantage to having these methods be generic if they are only ever passed objects;
or cast val from object to T before invoking FooStruct / FooClass.
Why does it seem impossible to do what you're asking? You are trying to convert an expression that is statically typed object (namely val) into something that is statically typed <T> where T : struct or <T> where T : class (in order to call the respective extension method on such a T). That is, you are trying to dynamically introduce a new type variable inside your foreach loop. Unfortunately, the only way to introduce a type variable is to declare it in advance, i.e. as some generic type parameter T in the method's signature; and then it is not the code inside your method that gets to choose what actual type it stands for—it's the calling code that determines T.
Reflection-based solution:
// determine which method ought to be called based on `val`'s run-time type.
// (for C# 6 and later, use the `nameof` operator instead of hard-coding method names)
Type type = val.GetType();
string fooName = type.IsValueType ? "FooStruct" : "FooClass";
// bind to the generic method and supply the type argument for it:
// (I'm assuming that your extension methods are defined in `FooMethodsClass`.)
MethodInfo fooOpen = typeof(FooMethodsClass).GetMethod(fooName, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
MethodInfo foo = fooOpen.MakeGenericMethod(new Type[] { type });
// invoke the generic (extension) method with `val` as the `this` argument:
foo.Invoke(null, new object[] { val });
The dynamic variable support will set T appropriately. I use this trick regularly. Try it like this:
Type type = x.GetType();
foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
dynamic val = fieldInfo.GetValue(value);
object obj = type.IsValueType ? Utilities.FooStruct(val) : Utilities.FooClass(val);
fieldInfo.SetValue(x, obj);
}
Apparently you can call the methods with reflection and they work without a problem:
using System;
using System.Reflection;
namespace DemoDynamicT
{
public static class Utilities
{
public static T FooStruct<T>(this T value) where T:struct
{
return default(T);
}
public static T FooClass<T>(this T value) where T : class
{
return default(T);
}
}
public class Program
{
class TestClass
{
public TestStruct StructField;
}
struct TestStruct
{
public int x;
int y;
}
public static void Main()
{
var x = new TestClass();
Type type = x.GetType();
foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
var val = fieldInfo.GetValue(x);
var methodInfo = typeof(Utilities).GetMethod(fieldInfo.FieldType.IsValueType ? "FooStruct" : "FooClass");
var toBeCalled = methodInfo.MakeGenericMethod(fieldInfo.FieldType);
object obj = toBeCalled.Invoke(null, new [] {val});
fieldInfo.SetValue(x, obj);
}
}
}
}
I don't think you can do this directly. You can try workaround like this:
public static class Utilities
{
public static ValueType FooStruct(this ValueType value)
{
//put your code here
return default(ValueType);
}
public static object FooClass(this object value)
{
//put your code here
return null;
}
public static T FooStruct<T>(this T value) where T: struct
{
return (T) FooStruct(value);
}
public static T FooClass<T>(this T value) where T: class
{
return (T) FooClass(value);
}
}
public class Program
{
class TestClass
{
public TestStruct StructField;
}
struct TestStruct
{
int x;
int y;
}
public static void Main()
{
var x = new TestClass();
Type type = x.GetType();
foreach (var fieldInfo in type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
var val = fieldInfo.GetValue(x);
object obj = fieldInfo.FieldType.IsValueType ? ((ValueType)val).FooStruct() : val.FooClass();
fieldInfo.SetValue(x, obj);
}
//Generic call
var structVar = new TestStruct();
structVar.FooStruct();
}
}

Get value of a public static field via reflection

This is what I've done so far:
var fields = typeof (Settings.Lookup).GetFields();
Console.WriteLine(fields[0].GetValue(Settings.Lookup));
// Compile error, Class Name is not valid at this point
And this is my static class:
public static class Settings
{
public static class Lookup
{
public static string F1 ="abc";
}
}
You need to pass null to GetValue, since this field doesn't belong to any instance:
fields[0].GetValue(null)
You need to use Type.GetField(System.Reflection.BindingFlags) overload:
http://msdn.microsoft.com/en-us/library/4ek9c21e.aspx
For example:
FieldInfo field = typeof(Settings.Lookup).GetField("Lookup", BindingFlags.Public | BindingFlags.Static);
Settings.Lookup lookup = (Settings.Lookup)field.GetValue(null);
The signature of FieldInfo.GetValue is
public abstract Object GetValue(
Object obj
)
where obj is the object instance you want to retrieve the value from or null if it's a static class. So this should do:
var props = typeof (Settings.Lookup).GetFields();
Console.WriteLine(props[0].GetValue(null));
Try this
FieldInfo fieldInfo = typeof(Settings.Lookup).GetFields(BindingFlags.Static | BindingFlags.Public)[0];
object value = fieldInfo.GetValue(null); // value = "abc"

Categories