I'm trying to test private methods in a Unit test project. So far it's going great, but I hit a bump, when I have to test a method with an out parameter. The signature for that method is:
private bool GotSSI(out SSI ssi, RSI rsi)
{
~code omitted~
}
And the unittest (the part that is not working) looks like this:
SSI ssi = null;
object[] p = new object[]{ssi,rsi};
Type[] t = new Type[] { typeof(SSI).MakeByRefType(), typeof(RSI) };
actual = (bool) privateTarget.Invoke("GotSSI",t,p);
The GotSSI method work. I've tested it in debug mode within the unit test and I can see that the 'ssi' out variable is set inside the method, before returning it's true or false value. But when the test returns to it's own code, the 'ssi' variable is still null. So the problem is that the object I created in the "GotSSI" method, is not parsed out of the PrivateObject invoke method.
Anyone knows what I am missing?
Update (Solution by Rafal)
Rafal's solution work perfectly and here is how I implemented the solution.
I created a delegate:
delegate bool GotSSIInternal(out SSI ssi, RSI rsi);
And when I have created the object I wanted to test, I build the delegate (target is the object i'm testing):
GotSSIInternal gotSSIInternal = (GotSSIInternal) Delegate.CreateDelegate(
typeof (GotSSIInternal),
target,
typeof(OfflineResolver).GetMethod("GotSSI", BindingFlags.NonPublic | BindingFlags.Instance));
After that is very simple to call the delegate:
actual = gotSSIInternal.Invoke(out ssi, rsi);
The solution is very simple and works like a charm.
Although the final solution that was accepted works, there is a much simpler way to do it. If you follow the link given in the accepted answer from Rafal, you will find a similar question to this one, with two answers. The second answer (with the most "useful" points) is the simpler of the two.
Here is a modified version of that answer specifically for a testing scenario:
//method to test is a private method of the class ClassTotest with signature
// TryGetCustomerData(List<Invoice> invoices, out CustomerData customerData)
//set up
var objToTest = new ClassToTest();
var invoices = GetInvoices();
CustomerData customerData = null;
//set up the arguments
var args = new object[] { invoices, customerData };
//get the MethodInfo of the method you want to test
var method = typeof(ClassToTest).GetMethod("TryGetCustomerData",
BindingFlags.NonPublic | BindingFlags.Instance);
//invoke it
var success = (bool)method.Invoke(objToTest, args);
//get back the customerData argument - the "out" parameter
var actual = args[1] as CustomerData;
your invocation of method with out parameter is wrong if you want to get the out value. See this on how to invoke it with reflection.
You need to ask yourself if you really need to test private methods? I personally do not test Private methods but it is all down to personal opinion (and it can get quite heated). There are numerous reasons / articles / opinions. A good SO thread can be found here.
An excerpt from the accepted answer is "A private method is an implementation detail that should be hidden to the users of the class. Testing private methods breaks encapsulation..."
The reason I do not test my private methods is because they are more likely to change than the public interface. If you cover all of your private methods it makes refactoring more complex (again, just my opinion). If you change a private method and the Public interface breaks you will know as your unit tests fail and you can then drill down.
That is just my opinion and I know many disagree so just putting it out there!
I can use PrivateObject to do this, although it is not technically a "return value", like:
object[] p = new object[] { null, rsi };
Type[] t = new Type[] { typeof(SSI).MakeByRefType(), typeof(RSI) };
actual = (bool)privateTarget.Invoke("GotSSI", t, p);
SSI ssi = p[0];
Actually the type array can be omitted if the method overload can be determined without it:
object[] p = new object[] { null, rsi };
actual = (bool)privateTarget.Invoke("GotSSI", p);
SSI ssi = p[0];
Just do this: https://instance-factory.com/?p=738
ClassWithPrivateMethods instance = new ClassWithPrivateMethods();
PrivateObject privateObject = new PrivateObject(instance);
object[] args
= new object[] { "some value", null /* placeholder for out param */ };
privateObject.Invoke("PrivateMethodHavingOutParameter", args);
var outParameterValue = args[1];
Related
There are a group of private methods in my class, and I need to call one dynamically based on an input value. Both the invoking code and the target methods are in the same instance. The code looks like this:
MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType);
dynMethod.Invoke(this, new object[] { methodParams });
In this case, GetMethod() will not return private methods. What BindingFlags do I need to supply to GetMethod() so that it can locate private methods?
Simply change your code to use the overloaded version of GetMethod that accepts BindingFlags:
MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType,
BindingFlags.NonPublic | BindingFlags.Instance);
dynMethod.Invoke(this, new object[] { methodParams });
Here's the BindingFlags enumeration documentation.
BindingFlags.NonPublic will not return any results by itself. As it turns out, combining it with BindingFlags.Instance does the trick.
MethodInfo dynMethod = this.GetType().GetMethod("Draw_" + itemType,
BindingFlags.NonPublic | BindingFlags.Instance);
And if you really want to get yourself in trouble, make it easier to execute by writing an extension method:
static class AccessExtensions
{
public static object call(this object o, string methodName, params object[] args)
{
var mi = o.GetType ().GetMethod (methodName, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance );
if (mi != null) {
return mi.Invoke (o, args);
}
return null;
}
}
And usage:
class Counter
{
public int count { get; private set; }
void incr(int value) { count += value; }
}
[Test]
public void making_questionable_life_choices()
{
Counter c = new Counter ();
c.call ("incr", 2); // "incr" is private !
c.call ("incr", 3);
Assert.AreEqual (5, c.count);
}
Microsoft recently modified the reflection API rendering most of these answers obsolete. The following should work on modern platforms (including Xamarin.Forms and UWP):
obj.GetType().GetTypeInfo().GetDeclaredMethod("MethodName").Invoke(obj, yourArgsHere);
Or as an extension method:
public static object InvokeMethod<T>(this T obj, string methodName, params object[] args)
{
var type = typeof(T);
var method = type.GetTypeInfo().GetDeclaredMethod(methodName);
return method.Invoke(obj, args);
}
Note:
If the desired method is in a superclass of obj the T generic must be explicitly set to the type of the superclass.
If the method is asynchronous you can use await (Task) obj.InvokeMethod(…).
Reflection especially on private members is wrong
Reflection breaks type safety. You can try to invoke a method that doesn't exists (anymore), or with the wrong parameters, or with too much parameters, or not enough... or even in the wrong order (this one my favourite :) ). By the way return type could change as well.
Reflection is slow.
Private members reflection breaks encapsulation principle and thus exposing your code to the following :
Increase complexity of your code because it has to handle the inner behavior of the classes. What is hidden should remain hidden.
Makes your code easy to break as it will compile but won't run if the method changed its name.
Makes the private code easy to break because if it is private it is not intended to be called that way. Maybe the private method expects some inner state before being called.
What if I must do it anyway ?
There are so cases, when you depend on a third party or you need some api not exposed, you have to do some reflection. Some also use it to test some classes they own but that they don't want to change the interface to give access to the inner members just for tests.
If you do it, do it right
Mitigate the easy to break:
To mitigate the easy to break issue, the best is to detect any potential break by testing in unit tests that would run in a continuous integration build or such. Of course, it means you always use the same assembly (which contains the private members). If you use a dynamic load and reflection, you like play with fire, but you can always catch the Exception that the call may produce.
Mitigate the slowness of reflection:
In the recent versions of .Net Framework, CreateDelegate beat by a factor 50 the MethodInfo invoke:
// The following should be done once since this does some reflection
var method = this.GetType().GetMethod("Draw_" + itemType,
BindingFlags.NonPublic | BindingFlags.Instance);
// Here we create a Func that targets the instance of type which has the
// Draw_ItemType method
var draw = (Func<TInput, Output[]>)_method.CreateDelegate(
typeof(Func<TInput, TOutput[]>), this);
draw calls will be around 50x faster than MethodInfo.Invoke
use draw as a standard Func like that:
var res = draw(methodParams);
Check this post of mine to see benchmark on different method invocations
Are you absolutely sure this can't be done through inheritance? Reflection is the very last thing you should look at when solving a problem, it makes refactoring, understanding your code, and any automated analysis more difficult.
It looks like you should just have a DrawItem1, DrawItem2, etc class that override your dynMethod.
Invokes any method despite its protection level on object instance. Enjoy!
public static object InvokeMethod(object obj, string methodName, params object[] methodParams)
{
var methodParamTypes = methodParams?.Select(p => p.GetType()).ToArray() ?? new Type[] { };
var bindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
MethodInfo method = null;
var type = obj.GetType();
while (method == null && type != null)
{
method = type.GetMethod(methodName, bindingFlags, Type.DefaultBinder, methodParamTypes, null);
type = type.BaseType;
}
return method?.Invoke(obj, methodParams);
}
I think you can pass it BindingFlags.NonPublic where it is the GetMethod method.
Could you not just have a different Draw method for each type that you want to Draw? Then call the overloaded Draw method passing in the object of type itemType to be drawn.
Your question does not make it clear whether itemType genuinely refers to objects of differing types.
It should be noted that calling from a derived class can be problematic.
Error prone:
this.GetType().GetMethod("PrivateTestMethod", BindingFlags.Instance | BindingFlags.NonPublic)
Correct:
typeof(CurrentClass).GetMethod("PrivateTestMethod", BindingFlags.Instance | BindingFlags.NonPublic)
Read this (supplementary) answer (that is sometimes the answer) to understand where this is going and why some people in this thread complain that "it is still not working"
I wrote exactly same code as one of the answers here. But I still had an issue. I placed break point on
var mi = o.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance );
It executed but mi == null
And it continued behavior like this until I did "re-build" on all projects involved. I was unit testing one assembly while the reflection method was sitting in third assembly. It was totally confusing but I used Immediate Window to discover methods and I found that a private method I tried to unit test had old name (I renamed it). This told me that old assembly or PDB is still out there even if unit test project builds - for some reason project it tests didn't built. "rebuild" worked
i'm kind of struggling with a ML.NET related problem here and am hoping that someone might can help me.
I'm developing an (.NET core) application which consumes ONNX models whose inputs are unknown at compile time. What I've done so far:
I'm able to compile an assembly during runtime which contains the input class definition and load this definition:
var genericSampleAssembly =
AssemblyLoadContext.Default.LoadFromAssemblyPath("/app/storage/sample.dll");
Type genericInputClass = genericSampleAssembly.GetType("GenericInterface.sample");
Also I'm able to train a model with that dynamically created Inputtype using Reflection:
MethodInfo genericCreateTextLoader = typeof(TextLoaderSaverCatalog).GetMethods()
.Where(_ => _.Name == "CreateTextLoader")
.Single(_ => _.GetParameters().Length == 6)
.MakeGenericMethod(_genericInputClass);
TextLoader reader = genericCreateTextLoader.Invoke(_mlContext.Data, new object[] { _mlContext.Data, false, ',', true, true, false}) as TextLoader;
IDataView trainingDataView = reader.Read("sample.txt");
var debug = trainingDataView.Preview();
var pipeline = _mlContext.Transforms.Concatenate("Features", _featureNamesModel
.AppendCacheCheckpoint(_mlContext)
.Append(_mlContext.Regression.Trainers.StochasticDualCoordinateAscent(labelColumn: "Label",
featureColumn: "Features")));
ITransformer model = pipeline.Fit(trainingDataView);
But I'm not able to make predictions by now because I don't know how to invoke the PredictionEngine. I'm able to get a generic version of that CreatePredictionEngine method but don't now how to cast that returning object to an PredictionEngine and finally invoke the Predict method:
MethodInfo genericCreatePredictionEngineMethod = typeof(PredictionEngineExtensions).GetMethods()
.Single(_ => _.Name == "CreatePredictionEngine")
.MakeGenericMethod(new Type[] { genericInputClass, typeof(GenericPrediction)});
var predictionEngine = genericCreatePredictionEngineMethod.Invoke(_model, new object[] {_model, _mlContext, null, null});
predictionEngine is of Type object in this case but I need to cast it to something like PredictionEngine<genericInputClass, GenericPrediction>, while genericInputClass is the class from that dynamically created assembly and GenericPrediction is a simple class with one output I know at compile time.
So whats missing is something like:
MethodInfo genericCreatePredictionEngineMethod = typeof(PredictionEngineExtensions).GetMethods()
.Single(_ => _.Name == "CreatePredictionEngine")
.MakeGenericMethod(new Type[] { genericInputClass, typeof(GenericPrediction)});
PredictionEngine<genericInputClass, GenericPrediction> predictionEngine = genericCreatePredictionEngineMethod.Invoke(_model, new object[] {_model, _mlContext, null, null}) as PredictionEngine<genericInputClass, GenericPrediction>;
float prediction = predictionEngine.Predict(genericInputClass inputValue);
Does anyone had a similar problem or has any other hints?
I might missed some lines, because I copy/pasted and simplified it pretty quick. In case something is missing, I'll provide it later.
EDIT: I constructed a minimal example to show the basic problem. As mentioned in the comments dynamic isn't possible due to the ML.NET methods.
using System;
using System.Linq;
using System.Runtime.Loader;
namespace ReflectionSample
{
class Program
{
static void Main(string[] args)
{
// Example with a known Type
var extendedClass = new DummyExtendedClass();
SampleGenericClass<String> sampleGenericClass = extendedClass.SampleGenericExtensionMethod<String>();
sampleGenericClass.SampleMethod("");
// At compile time unknown Type - In reality the loaded dll is compiled during runtime
var runtimeCompiledSampleAssembly =
AssemblyLoadContext.Default.LoadFromAssemblyPath("C:/Program Files (x86)/Reference Assemblies/Microsoft/Framework/.NETCore/v4.5/System.IO.dll");
var compileTimeUnknownClass = runtimeCompiledSampleAssembly.GetType("System.IO.TextReader");
var reflectedExtensionMethod = typeof(Extensions).GetMethods()
.Single(_=>_.Name== "SampleGenericExtensionMethod")
.MakeGenericMethod(new[] {compileTimeUnknownClass});
var howToCastThis = reflectedExtensionMethod.Invoke(extendedClass, new object[] {extendedClass});
// whats missing:
// howToCastThis is of Type object but should be SampleGenericClass<System.IO.TextReader>
// I need to be able to call howToCastThis.SampleMethod(new System.IO.TextReader)
// I thought this might work via reflecting SampleMethod and MakeGenericMethod
Console.ReadKey();
}
}
public sealed class SampleGenericClass<T>
{
public void SampleMethod(T typeInput)
{
Console.WriteLine($"Invoking method worked! T is of type {typeof(T)}");
}
}
public static class Extensions
{
public static SampleGenericClass<T> SampleGenericExtensionMethod<T>(this DummyExtendedClass extendedClass)
{
Console.WriteLine($"Invoking extension method worked! T is of type {typeof(T)}");
return new SampleGenericClass<T>();
}
}
public class DummyExtendedClass
{
public DummyExtendedClass() { }
}
}
Greetings
Sven
Nice job on the MCVE. I was able to invoke SampleMethod; it turns out there's not much to it and it's probably less complicated than you imagined.
In your example, the object you're getting, howToCastThis, is of a type that's already close-constructed. As long as you start from that instance's type, you don't need to use MakeGenericMethod.
Let's say you have an object instance, compileTimeTypeUnknownInstance, for the parameter you want to pass to SampleMethod. Since System.IO.TextReader is abstract, compileTimeTypeUnknownInstance would have to be of a concrete, TextReader-derived type. With those conditions satisfied, the following works:
var sampleMethod = howToCastThis.GetType().GetMethods()
.Single(mi => mi.Name == "SampleMethod");
sampleMethod.Invoke(howToCastThis, new object[] { compileTimeTypeUnknownInstance });
SampleMethod reports that T is of type System.Text.TextReader.
Again, howToCastThis is of a close-constructed type, therefore, so is the method you want.
Note: Although not the case here, a method in a close-constructed type can introduce additional type arguments so you still would have to call MakeGenericMethod to close-construct the method in that case.
Now, if I were to try to translate this to your situation, I'm guessing it would look something like this:
var predictMethod = predictionEngine.GetType().GetMethods()
.Single(mi => mi.Name == "Predict");
float prediction = (float)predictMethod.Invoke(predictionEngine, new object[] { inputValue });
I'm not sure about the syntax in your pseudocode call to Predict. I assumed that inputValue was the only parameter and genericInputClass was only there to indicate that it was a type argument in the close-constructed type. If this was incorrect, you'll need to figure out what actually goes in that object[] argument.
I've found lots of info on passing parameters to methods and found that having the method use params Object[] args to be a great (and sometimes only) way to do this.
i.e. sample method:
public void someMethod(params object[] args)
{
//do something
}
But when passing the parameter object like this to a Com Method, it doesn't work:
object[] passParameters = new object[2];
passParameters[0] = "test1";
passParameters[1] = "test2";
//Calling method compiled with with CodeDom
MethodInfo method = classObject.GetType().GetMethod("someMethod");
object dynamicOutput = method.Invoke(classObject, passParameters);
For it to work, I have found that I need to pass the parameter object as a new Object:
object dynamicOutput = method.Invoke(classObject,(new object[] { passParameters });
Can anyone please explain to me why I need to do this and what the reasoning is behind it? Thanks.
They don't. You can just use them as
someMethod("test1", "test2", ... )
BUT. If you're creating an array beforehand, it has to be passed differently, as you encountered
I've come to realise that the original passParameters object in the example contains two elements, as we know:
passParameters[0] = "test1";
passParameters[1] = "test2";
However, when the array is passed to the Com method, it requires being passed as so:
new object[] { passParameters })
My understanding of this is, that it creates a new object array which has put the existing 'passParameters' array into its first element [0] (effectively creating a new 2d array):
passParameters[0][0] = "test1";
passParameters[0][1] = "test2";
The method MethodInfo class in my question, required a single object passed to the Invoke method, which meant that the original 'passParameters' object with its two elements had too many arguments. By passing it inside a new object, this passes all of the elements as a single object, but containing an array of those parameters.
I am implementing a DynamicObject. In the TryInvokeMethod, in addition to the arguments ( passed in to the method), I also need the names for the parameters if they have been used.
I can see that binder.CallInfo.ArgumentNames does indeed provides the names, but I am not able to associate them with the values. Is there any way to do so, or am I hoping against hope:
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
var names = binder.CallInfo.ArgumentNames;
foreach (var arg in args)
{
arguments.Add(new Argument(arg));
}
//I need to associate the names and the args
result = this;
return true;
}
So for example if I do a call like:
myDynamicObject.DynamicInvoke("test", something: "test2")
I have test and test2, and also something, but I am not able to get the information that something was the name for test2 and test had no name.
I had to use the fact that named arguments occur only after the non-named ones are specified ( thanks to user629926 for pointing to the obvious) and initial code:
var names = binder.CallInfo.ArgumentNames;
var numberOfArguments = binder.CallInfo.ArgumentCount;
var numberOfNames = names.Count;
var allNames = Enumerable.Repeat<string>(null, numberOfArguments - numberOfNames).Concat(names);
arguments.AddRange(allNames.Zip(args, (flag, value) => new Argument(flag, value)));
I am reading and writing data to and from a file. The data in the file can be floats, doubles, ints etc. The type is not known until runtime. I will refer to data type stored in the file as Tin. Data is read into or written from arrays of type Tout. This type too is not known until runtime.
The code sequence is something like this. In the Open method Tin and Tout are known, we can create read and write methods for the known data types.
Open(...)
{
MethodInfo ReadMethod = typeof(...)GetMethod("ReadGeneric").MakeGenericMethod(new Type[] {typeof(Tin), typeof(Tout)}));
}
The read write loops repeat millions of times and rely on reflection to invoke the appropriate methods as shown below.
Read loop
{
var values = (Tout[])ReadMethod.Invoke(this,new object[]{index});
process ...
}
When examining this code using a performance profiler I find that c collosal amount if time is spent just invoking the runtime read write methods.
How do I speed this up.
Yes, this is due to the fact that the reflection API is thousands of times slower than direct method calls. There are some interesting techniques to work around this however. Check out Jon Skeet's article on using delegates to cache reflection.
There is a static setup cost but once you have done that the time to invoke the delegate repeatedly is equivalent to virtual method calls.
There are also some pre-packaged frameworks to achieve the same thing.
This'll do anything for ya, almost as fast as a direct call.
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
public class FastMethodInfo
{
private delegate object ReturnValueDelegate(object instance, object[] arguments);
private delegate void VoidDelegate(object instance, object[] arguments);
public FastMethodInfo(MethodInfo methodInfo)
{
var instanceExpression = Expression.Parameter(typeof(object), "instance");
var argumentsExpression = Expression.Parameter(typeof(object[]), "arguments");
var argumentExpressions = new List<Expression>();
var parameterInfos = methodInfo.GetParameters();
for (var i = 0; i < parameterInfos.Length; ++i)
{
var parameterInfo = parameterInfos[i];
argumentExpressions.Add(Expression.Convert(Expression.ArrayIndex(argumentsExpression, Expression.Constant(i)), parameterInfo.ParameterType));
}
var callExpression = Expression.Call(!methodInfo.IsStatic ? Expression.Convert(instanceExpression, methodInfo.ReflectedType) : null, methodInfo, argumentExpressions);
if (callExpression.Type == typeof(void))
{
var voidDelegate = Expression.Lambda<VoidDelegate>(callExpression, instanceExpression, argumentsExpression).Compile();
Delegate = (instance, arguments) => { voidDelegate(instance, arguments); return null; };
}
else
Delegate = Expression.Lambda<ReturnValueDelegate>(Expression.Convert(callExpression, typeof(object)), instanceExpression, argumentsExpression).Compile();
}
private ReturnValueDelegate Delegate { get; }
public object Invoke(object instance, params object[] arguments)
{
return Delegate(instance, arguments);
}
}
Profile to find the solution that matches your expectations :
.Net Framework offers plenty of methods to invoke dynamically methods. However they don't perform equally in terms of performance and they are not equally easy to use.
CreateDelegate may be what you're looking for
In the recent versions of .Net Framework, CreateDelegate beat by a factor 50 the MethodInfo invoke:
// The following should be done once since this does some reflection
var method = typeof (...).GetMethod("ReadGeneric");
// Here we create a Func that targets the instance of type which has the
// ReadGeneric method
var func = (Func<Tin, Tout[]>)_method.CreateDelegate(typeof(Func<Tin, Tout[]>), target);
// Func will be 50x faster than MethodInfo.Invoke
// use func as a standard Func like
// var tout = func(index);
Check this post of mine to see benchmark on different method invocations