Issue is simple but quite hard to bypass - I need to test private method without simply changing code to make it public. Doing it wouldn't be the end of the world, but this class contains one public method and set of private methods dedicated to that one public method, and changing it would be bad practice.
I have managed to found "solution" online, but it does not seem to work. Test fails with exception System.Reflection.TargetException : Object does not match target type..
Here is simplified code:
private Class _class;
private List<Item> _list;
private List<Item> _resultList;
[SetUp]
public void SetUp()
{
_class = new Class();
_list = new List<Item>();
_resultList = new List<Item>();
//do stuff to prepare data
}
[Test]
public void TestMethod_Equal()
{
var method = GetMethod("PrivateMethodName");
var result = method.Invoke(this, new object[] { _list }); //this private method needs `List<item>`
Assert.That(_resultList, Is.EqualTo(result));
}
private MethodInfo GetMethod(string methodName) //the online solution
{
if (string.IsNullOrWhiteSpace(methodName))
Assert.Fail("methodName cannot be null or whitespace");
var method = this._class.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
if (method == null)
Assert.Fail(string.Format("{0} method not found", methodName));
return method;
}
You need an instance of the class to be able to invoke the method against that instance. You also need to use the same type of said instance when locating the MethodInfo for the class. I've adapted your code to an example below:
void Main()
{
var myInstanceUnderTest = new MyConcreteClass();
var method = myInstanceUnderTest.GetType().GetPrivateMethod("SomePrivateMethod");
method.Invoke(myInstanceUnderTest, null);
}
public class MyConcreteClass
{
private void SomePrivateMethod()
{
Console.WriteLine("I ran!");
}
}
public static class Helpers
{
public static MethodInfo GetPrivateMethod(this Type myType, string methodName) //the online solution
{
if (string.IsNullOrWhiteSpace(methodName))
throw new Exception("methodName cannot be null or whitespace");
var method = myType.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
if (method == null)
throw new Exception(string.Format("{0} method not found", methodName));
return method;
}
}
Related
Based on this old but very usefull article by the legendary Jon Skeet, I wrote a few methods to genereate Action Delegates from MethodInfos for faster invokations. But I ran into an issue, where I am unable to make any progress. See the example below:
public class DataContainer
{
public List<int> myList;
public DataContainer()
{
myList = new List<int>() { 1, 2, 3, 4 };
}
}
public static class ExtensionMethods
{
public static void DoStuff<T>(this IList<T> items)
{
}
}
public class Example
{
private Action<object> doStuffQuickly;
public void Test()
{
var fieldInfo = typeof(DataContainer).GetField("myList");
var doStuffMethod = typeof(ExtensionMethods).GetMethod("DoStuff", BindingFlags.Public | BindingFlags.Static);
var listType = typeof(IList<>).MakeGenericType(fieldInfo.FieldType.GenericTypeArguments);
doStuffQuickly = QuickAccess.CreateWeakActionWithOneParam(doStuffMethod, listType);
var data = new DataContainer();
var list = fieldInfo.GetValue(data);
doStuffQuickly(list);
}
}
public static class QuickAccess
{
private static MethodInfo _weak1ParamActionCreator;
private static MethodInfo Weak1ParamActionCreator => _weak1ParamActionCreator
??= typeof(QuickAccess).GetMethod(nameof(CreateWeakExplicit1ParamAction), BindingFlags.Static | BindingFlags.NonPublic);
public static Action<object> CreateWeakActionWithOneParam(MethodInfo methodInfo, Type paramType0 = null)
{
var parameters = methodInfo.GetParameters();
paramType0 ??= parameters[0].ParameterType;
var creationMethod = Weak1ParamActionCreator.MakeGenericMethod(paramType0);
return (Action<object>)creationMethod.Invoke(null, new object[] { methodInfo });
}
private static Action<object> CreateWeakExplicit1ParamAction<TValue>(MethodInfo methodInfo)
{
var action = CreateStrongExplicit1ParamAction<TValue>(methodInfo);
return (object value) => action((TValue)value);
}
private static Action<TValue> CreateStrongExplicit1ParamAction<TValue>(MethodInfo methodInfo)
{
//Debug.Log(methodInfo.GetParameters()[0].ParameterType.Name + " <-> " + typeof(TValue).Name);
//Debug.Log(PrintTypes(methodInfo.GetParameters()[0].ParameterType.GenericTypeArguments) + " <-> "
// + PrintTypes(typeof(TValue).GenericTypeArguments));
return (Action<TValue>)Delegate.CreateDelegate(typeof(Action<TValue>), methodInfo);
}
private static string PrintTypes(Type[] types)
{
return string.Join(", ", types.Select(t => t.Name));
}
}
This fails with ArgumentException: method arguments are incompatible when trying to create the delegate.
The commented logs print IList`1 <-> IList`1 and T <-> Int32, which made me think that maybe
var listType = typeof(IList<>).MakeGenericType(fieldInfo.FieldType.GenericTypeArguments);
should instead simply be
var listType = typeof(IList<>);
but that is causing an InvalidOperationException: Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.
I don't know how to proceed from here. Any help will be appreciated.
If I understand the code correctly, listType would be a IList<int>, so DoStuff would be DoStuff<IList<int>>. I would expect it to be DoStuff<int>
So the correct version should be
var listItemType = fieldInfo.FieldType.GenericTypeArguments[0];
doStuffMethod = doStuffMethod.MakeGenericMethod(listItemType);
doStuffQuickly = QuickAccess.CreateWeakActionWithOneParam(doStuffMethod);
I would highly recommend running your code in a debugger and inspect your values in every step to confirm all your reflection types look like you expect. Reflection is difficult, so it is really useful to be able to confirm any assumptions.
I have some problems with my project.
I want to call one method from private Property like private clsBUS_DEMO prop_DEMO
clsBUS_DEMO has a Method, which Name is public void SayHello().
This is my code
PropertyInfo p = this.GetType().GetProperty("SayHello");
p is null because program can't find prop_DEMO
Can anybody help me about this?
clsBUS_DEMO prop_DEMO is not a property, it's a Field. You need to use GetFields to get it and also since it's private you need to pass BindingFlags.NonPublic and BindingFlags.Instance.
Here is a sample of how you should do it
static void Main(string[] args)
{
Bar bar = new Bar();
Foo foo = (Foo)bar.GetType().GetField("a", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(bar);
foo.GetType().GetMethod("ShowMessage").Invoke(foo,new object[] { });
}
public class Bar
{
private Foo a;
public Bar()
{
a = new Foo();
}
}
public class Foo
{
public void ShowMessage()
{
Console.WriteLine("Hello World!");
}
}
Okay guys!
I'm done :)
I just Create Property get{} set{} and use this code :D
PropertyInfo p = this.GetType().GetProperty("LoaiSP_BUS", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
Thanks all!
Call a method of private property? Not sure if I understood what you want, it would be useful to have the class that represent you object. Do you mean call a property that returns an object and then call a method of that object?
Anyways, I think there's a lot information out there about that topic, for example:
How do I use reflection to invoke a private method?
Find a private field with Reflection?
class MyClass1
{
public MyClass1()
{
Prop = new MyClass2();
}
public MyClass2 Prop { get; set; }
}
class MyClass2
{
private int Test()
{
return 5;
}
}
static void Main(string[] args)
{
var obj = new MyClass1();
var obj2 = obj.Prop;
var propInfo = obj.GetType().GetProperty("Prop");
var obj2Reflection = propInfo.GetValue(obj, null);
var dynMethod = obj2.GetType().GetMethod("Test", BindingFlags.NonPublic | BindingFlags.Instance);
var obj2Return = dynMethod.Invoke(obj2, null);
}
I want to get a method by reflection,but the method has multiple overloads..and the method's parameters is a generic type..How can I do?
class Program
{
static void Main(string[] args)
{
test obj = new test();
Type[] types = { typeof(string) };
var method = obj.GetType().GetMethod("Say", BindingFlags.Instance | BindingFlags.NonPublic, null, types, null);
method.Invoke(obj, new object[] { "hello world" });
Console.ReadKey();
}
}
public class test
{
private void Say(string value)
{
Console.WriteLine(value);
}
private void Say<T>(T t)
{
Console.WriteLine(t);
}
}
I can get private void Say(string value)..but I want to get private void Say<T>(T t)..
Type[] types = { typeof(string) }; Here how to set up here?
Based on the comments, I would rather go for a solution like:
public static MethodInfo GetGenericMethod(object obj, string methodName, Type genericParameter)
{
var method = obj.GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic).FirstOrDefault(m => m.Name.Equals(methodName) && m.IsGenericMethod);
return method.MakeGenericMethod(genericParameter);
}
And then call it with something like:
GetGenericMethod(obj, "Say", typeof(string));
You will then be able to invoke it like any other methods.
There are you ways.
Get all methods and find that one you're looking for
obj.GetType().GetMethods().Single(m=>m.GetParameters().Length = /* parameter count*/ && /* next condition */);
Use Expression tree
In my opinion is nicer and less error prone but can be used only when you known which method you want in compile time.
You need some helper method that extract Method for expression tree.
public static MethodInfo Method(Expression<Action> methodAccess)
{
return ((MethodCallExpression)methodAccess.Body).Method;
}
Then you can use it like this:
Get(()=>obj.Say<string>("My param")).GetGenericMethodDefinition();
Compiler will take care of selecting method and helper method will extract MethodInfo from expression tree. GetGenericMethodDefinition() call will give you open-generic version of selected method.
Say I have the following method:
private static void SetLastModifiedTimeUser<TEntity>(TEntity entity) where TEntity : class
{
PropertyInfo propertyInfo;
propertyInfo = entity.GetType().GetProperty("LastModifiedUser");
if (propertyInfo != null)
propertyInfo.SetValue(entity, IdentityHelper.UserName, null);
}
As you can see, the method accepts a generic type. Every class passed to this method will contain a property named 'LastModifiedUser'. Is there a way I can access this property without using reflection? I don't think there is, but I thought I'd ask.
Yes, if all your entities have LastModifiedUser property, then you can make all entities inherit from base class, or implement some interface like
public interface IModifyable
{
string LastModifiedUser { get; set; }
}
Then just add this constraint (or make your method non-generic, accepting IModifyable)
where TEntity : class, IModifyable
And your code will look like:
private static void SetLastModifiedTimeUser<TEntity>(TEntity entity)
where TEntity : class, IModifyable
{
entity.LastModifiedUser = IdentityHelper.UserName;
}
Have your class inherit from an interface that defines a LastModifiedUser property.
public interface ILastModifiedUser
{
public string LastModifiedUser { get; set; }
}
Change your method declaration to
private static void SetLastModifiedTimeUser(ILastModifiedUser entity)
If you can't modify all the classes to implement a common interface you can use dynamic
private static void SetLastModifiedTimeUser<TEntity>(TEntity entity) where TEntity : class
{
dynamic d = entity;
d.LastModifiedUser = IdentityHelper.UserName;
}
Otherwise it is as simple as shown by Robert Harvey.
If you can't add an interface to your objects, consider this approach.
The first time it encounters each Type (TEntity), it looks up the property and gets the property's SetMethod. Then, on each use, it creates invokes the method.
var one = new EntityOne();
LastModifiedTimeUserSetter.Set(one);
Console.WriteLine(one.LastModifiedUser);
public static class LastModifiedTimeUserSetter
{
public static void Set<TEntity>(TEntity entity)
{
var method = Properties.GetOrAdd(typeof (TEntity), GetSetMethod);
var action = (Action<string>) Delegate.CreateDelegate(typeof (Action<string>), entity, method);
action(IdentityHelper.UserName);
}
static MethodInfo GetSetMethod(Type type)
{
var prop = type.GetProperty("LastModifiedUser");
if (prop == null)
return null;
return prop.GetSetMethod();
}
static readonly ConcurrentDictionary<Type, MethodInfo> Properties = new ConcurrentDictionary<Type, MethodInfo>();
}
Going further
There is a way to further improve performance by using the System.Reflection.Emit.MethodBuilder. And building a method that takes Entity and sets the property.
public static class LastModifiedTimeUserSetter
{
public static void Set<TEntity>(TEntity entity)
{
var action = (Action<TEntity>) Properties.GetOrAdd(typeof(TEntity), CreateDynamicSetMethodDelegate);
if(action != null)
action(entity);
}
static Delegate CreateDynamicSetMethodDelegate(Type type)
{
return CreateDynamicSetMethod(type).CreateDelegate(GetActionType(type));
}
static DynamicMethod CreateDynamicSetMethod(Type typeWithProperty)
{
var methodBuilder = new DynamicMethod(
"Dynamic_" + typeWithProperty.FullName + "_SetLastModifiedUser",
typeof (void),
new[] {typeWithProperty});
EmitSimpleAssignmentMethod(methodBuilder,
GetIdentityHelperUserNameGetMethod(),
GetPropertySetMethod(typeWithProperty));
return methodBuilder;
}
static MethodInfo GetIdentityHelperUserNameGetMethod()
{
return typeof(IdentityHelper).GetProperty("UserName").GetGetMethod();
}
static MethodInfo GetPropertySetMethod(Type type)
{
var prop = type.GetProperty("LastModifiedUser");
if (prop == null)
return null;
return prop.GetSetMethod();
}
static void EmitSimpleAssignmentMethod(DynamicMethod methodBuilder, MethodInfo getMethod, MethodInfo setMethod)
{
var il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.EmitCall(OpCodes.Call, getMethod, null);
il.EmitCall(OpCodes.Call, setMethod, null);
il.Emit(OpCodes.Ret);
}
static Type GetActionType(Type type)
{
return typeof (Action<string>).GetGenericTypeDefinition().MakeGenericType(type);
}
static readonly ConcurrentDictionary<Type, Delegate> Properties = new ConcurrentDictionary<Type, Delegate>();
}
See an Article from MSDN magazine about XBOX Live.
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.