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.
Related
How shall I call "MyMethod" using reflection in below code.
I have an existing C# code which has predefined structure which I am not allow to change. I need to call a method present in a class using reflection.
In below code "_instance" contains object of "Foo". I neeed to call "MyMethod" using "PropElementHighlighter" property in Consumer class.
using System.Reflection;
public class Foo
{
public void MyMethod(string Argument)
{
//some code
}
}
public class MainWindow
{
private Foo _instance;
public Foo PropElementHighlighter { get { return _instance; } }
}
public class Consumer
{
Type control = MainWindow.GetType();
PropertyInfo l_propInfo = control.GetProperty("PropElementHighlighter", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
MethodInfo l_HighlightMethodInfo = l_propInfo.PropertyType.GetMethod("MyMethod");
l_HighlightMethodInfo.Invoke(l_propInfo, new object[]{"Parameter1"});
}
I am getting error "Object does not match target type." while invoking method.
You are getting error because you are setting property info in object of method. Try to set value of property:
Type control = mainWindow.GetType();
PropertyInfo l_propInfo = control.GetProperty("PropElementHighlighter", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
var propertyValue = l_propInfo.GetValue(mainWindow);
MethodInfo l_HighlightMethodInfo = l_propInfo.PropertyType.GetMethod("MyMethod");
l_HighlightMethodInfo.Invoke(propertyValue, new object[] { "Parameter1" });
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();
}
}
I have class and interface:
public class TestClass : ITestInterface
{
public int GetStatus()
{
return -1;
}
}
public interface ITestInterface
{
int GetStatus();
}
and I would like to dynamically create subclass of TestClass which will look like:
public class TestClass2 : TestClass
{
public new int GetStatus()
{
return base.GetStatus();
}
}
I have some code which can create subclasses and overrides all virtual methods but when method is virtual final (GetStatus) I'm getting:
"Declaration referenced in a method implementation cannot be a final method."
Any ideas how it can be done?
PS: I can post code mentioned if you'd like.
EDIT 1:
'Some code':
public static T GetSubClass<T>() where T : class
{
var builder = DefineType<T>();
DefineOverrideMethods(builder, typeof(T));
var type = CreateType(builder);
return (T)Activator.CreateInstance(type);
}
private static TypeBuilder DefineType<T>() where T : class
{
return _moduleBuilder.DefineType("Proxy_" + typeof (T).Name,
TypeAttributes.Sealed | TypeAttributes.Class | TypeAttributes.Public, typeof (T));
}
private static void DefineOverrideMethods(TypeBuilder builder, Type type)
{
foreach (var virtualMethodInfo in GetVirtualMethods(type))
{
var parameters = GetMethodParametersTypes(virtualMethodInfo);
var newMethodInfo = DefineNewVirtualMethod(builder, virtualMethodInfo, parameters);
var il = newMethodInfo.GetILGenerator();
var local = EmitCreateLocal(il, newMethodInfo);
EmitCallBaseMethod(il, virtualMethodInfo);
EmitSaveReturnToLocal(il, local);
EmitReturnMethod(il, virtualMethodInfo, local);
builder.DefineMethodOverride(newMethodInfo, virtualMethodInfo);
}
}
private static IEnumerable<MethodInfo> GetVirtualMethods(Type type)
{
return type.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly).Where(q => q.IsVirtual);
}
private static Type[] GetMethodParametersTypes(MethodInfo virtualMethodInfo)
{
return virtualMethodInfo.GetParameters().Select(q => q.ParameterType).ToArray();
}
private static MethodBuilder DefineNewVirtualMethod(TypeBuilder builder, MethodInfo virtualMethodInfo, Type[] parameters)
{
return builder.DefineMethod(virtualMethodInfo.Name,
MethodAttributes.Public | MethodAttributes.Virtual,
virtualMethodInfo.ReturnType, parameters);
}
private static void EmitSaveReturnToLocal(ILGenerator il, LocalBuilder local)
{
il.Emit(OpCodes.Stloc_S, local);
il.Emit(OpCodes.Ldloc_S, local);
}
private static LocalBuilder EmitCreateLocal(ILGenerator il, MethodBuilder newMethodInfo)
{
return il.DeclareLocal(newMethodInfo.ReturnType);
}
private static Type CreateType(TypeBuilder builder)
{
builder.DefineDefaultConstructor(MethodAttributes.Public);
var type = builder.CreateType();
return type;
}
private static void EmitReturnMethod(ILGenerator il, MethodInfo methodInfo, LocalBuilder local)
{
il.Emit(OpCodes.Ldloc_S, local);
il.Emit(OpCodes.Ret);
}
private static void EmitCallBaseMethod(ILGenerator il, MethodInfo virtualMethodInfo)
{
ushort index = 0;
while (index < virtualMethodInfo.GetParameters().Length + 1)
il.Emit(OpCodes.Ldarg, index++);
il.Emit(OpCodes.Call, virtualMethodInfo);
}
Exception is throwed at var type = builder.CreateType();
EDIT 2:
#Rahul:
Language is C# and as you can see in method 'GetVirtualMethods' there is property 'IsVirtual'.
Property 'IsFinal' exists there too and returns true for 'GetStatus' method.
EDIT 3:
#Wim.van.Gool:
Yes you are right - I can not override non virtual methods. What I am trying to do here is to hide base implementation of 'GetStatus' with dummy implementation which calls base method.
Why it would be useful? Imagine that method 'GetSubClass' returns you a class that behaves like base but for example have added log methods before and after base implementation calls.
#Michał Komorowski:
Thank you for answer. It works, but only partially. Program do not throws error anymore but in this example:
ITestInterface obj = StaticClass.GetSubClass<TestClass>();
obj.GetStatus();
'GetStatus' method is called directly from base (TestClass) not from dynamically created subclass.
I tried to add: builder.AddInterfaceImplementation(typeof(ITestInterface)); but it did not make any difference.
EDIT 4:
#danish: Thank you for answer. It is now working. NewSlot saves problem.
Actually whole attribute data: MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual.
Thank you guys for helping. Unfortunately I can not mark both answers as a correct ones but both were significant for resolving problem.
Whenever a class implements an interface method, CLR needs that method to be marked as virtual and also final is set to true. However in reality this method is not really virtual. To get actual virtual methods, you need to check IsVirtual for true and IsFinal for false.
In your case, you are actually looking for hiding the intended behaviour. Hence a new method needs to be created and emitted for sub class. From what I understand, NewSlot method attribute will shadow the base class method(can someone confirm? I am not too sure about this one).
The problem is that you are actually trying to override a method that is not virtual. You have 2 options. The first one is to make TestClass.GetStatus method virtual. When you do it you will be able to override it. The second solution is to hide this method. It seems to me that your code will work if you:
Remove the following line builder.DefineMethodOverride(newMethodInfo, virtualMethodInfo);
In DefineNewVirtualMethod method use MethodAttributes.HideBySig instead of MethodAttributes.Virtual.
I have the following C# Code. A Base class and classes that inherit from that base class.
I use this Baseclasses in an special List. This List also has the Member ReadListAsXmlAs.
public class ResultSetBase
{
some Members
}
public class ResultSetBaseSweep : ResultSetBase
{
some other Members
}
public class ResultList<T> where T : ResultSetBase
{
public ResultList<T> ReadListAsXmlAs(params string[] path)
{
...
}
}
In an other methode I want to create an dynamic object of the Type ResultList. I know of which class the ResultList is, only at runtime. (e.g. ResulstSetBaseSweep, or any other inherited from ResultSetBase).
I create an dynamic Object of this Type. the following way.
Type myType = Type.GetType("Class in String Format");
Type listtype = typeof(ResultSaver.ResultList<>).MakeGenericType(myType);
object resultlist = Activator.CreateInstance(listtype);
Now i need to call the Methode ReadListAsXmlAs. As it is of type object, the compiler complains when when i try to call
resultlist.ReadListAsXmlAs(...);
So I tried to call it over Reflections:
myType.InvokeMember("ReadListAsXmlAs", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, resultlist, new object[] { filenames.ToArray() });
Then I get the compiler error: ReadListAsXmlAs not found! How is it done right?
I have found a solution to the problem:
Type myType = Type.GetType(LstBoxClass.SelectedItem.ToString());
Type listtype = typeof(ResultSaver.ResultList<>).MakeGenericType(myType);
object resultlist = Activator.CreateInstance(listtype);
MethodInfo method = listtype.GetMethod("ReadListAsXmlAs");
method.Invoke(resultlist, new Object[] {filenames.ToArray()});
I tried code below in .NET 3.5 but mi is null.
How to call private generic method so that type parameter can be passed at runtime?
If SaveEntityGeneric is marked as public this code works OK but I dont wat to make it public since it is only used in other method in same class to pass this class type using GetType().
using System.Reflection;
public class Main1
{
static void Main()
{
new Class1().Test();
}
}
class Class1
{
public void Test()
{
var mi = GetType().GetMethod("SaveEntityGeneric", BindingFlags.NonPublic);
// why mi is null ?
var gm = mi.MakeGenericMethod(GetType());
gm.Invoke(this, null);
}
void SaveEntityGeneric<TEntity>()
{
}
}
The binding flags are tricky to get right on this. Use BindingFlags.NonPublic | BindingFlags.Instance.
var mi = GetType().GetMethod("SaveEntityGeneric",
BindingFlags.NonPublic | BindingFlags.Instance);
var gm = mi.MakeGenericMethod(GetType());
gm.Invoke(this, null);
Simply make it internal, that will prevent from usage that method outside the assembly