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
Related
The problem I am having is that I would like to call a method from a string. Here is what I am doing:
Building My List of Strings (Methods) there are three different checkboxList objects in my UI
private List<string> MyTest = new List<string>();
private void AddSelectedMethods()
{
foreach(XName item in BaseTestList.CheckedItems)
{
MyTests.Add(item.ToString());
}
foreach (XName item in AdminTestList.CheckedItems)
{
MyTests.Add(item.ToString());
}
foreach (XName item in SubscriberTestList.CheckedItems)
{
MyTests.Add(item.ToString());
}
}
Here is the Caller. If I take out the Reflections call and reference the method directly everything works but I don't want to get into crating a huge list of if else statements.
private void StartSiteTest(object sender, DoWorkEventArgs e)
{
if (!BackWorker1.CancellationPending)
{
if (SiteToTest == "estatesales.vintagesoftware.local" || SiteToTest == "localhost")
{
es = new EstateSaleTests(site, Sites.First(i => i.SiteUrl == SiteToTest), BasePath, SiteToTest, UseCurrentCompanies);
foreach (string test in MyTests)
{
// <<<!!!!!!!! ------ The next line returns null ------ !!!!!!!>>>
MethodInfo thisMethod = es.GetType().GetMethod(test);
thisMethod.Invoke(es, null);
}
}
}
}
Any help on what I am doing wrong would be greatly appreciated.
!!!----- EDIT -----!!!
I'm an idiot. I had the class set to the list of strings but I forgot to rename my Methods Sorry about that. Yes the Methods were public and they are accessible I just have to rename them to the correct names now.
The call you use seems pretty acceptable, imo.
The thing is that GetType().GetMethod() is able to recover only public methods.
See this MSDN link.
In order to access methods with different acessors use this GetMethod(string, BindingFlags) overload.
Hope this helps.
I notice this has already been well-answered, but the following might still be of use.
Sometimes it is hard to find the method using reflection. You're currently just searching for public instance methods only. What I usually do when finding the method through reflection appears rather hard, is using GetMethods() with different binding flags and check by hand whether the expected methods are there.
Note that when you specify binding flags, you must also specify BindingFlags.InvokeMethod | BindingFlags.Instance. In addition, consider the following:
If the method is an instance method, use BindingFlags.Static
If you don't know whether you have the caption right ("CalcRoot" is different than "calcRoot") than use BindingFlags.IgnoreCase
If you think the method is protected, internal, private or protected internal, use BindingFlags.NonPublic
If you are not sure whether you use a derived type, use BindingFlags.FlattenHierarchy
If you are uncertain whether what you are looking for is a property, field or method, use GetMembers instead.
You can combine all flags with | to search for everything. With a little bit trial and error you'll eventually find the set of binding params that you need.
I want to call a method of a DLL via reflection (can't be sure that the other dll is loaded) but have problems with the parameters.
The method I want to call is
public void Add(DBTable table, String sField, DBValue value, SQLConditionType type)
in the MP-TVSeries project
What I tried is this:
// WindowPlugins.GUITVSeries
Assembly MPTVSeries = Assembly.Load("MP-TVSeries");
Type sqlConditionType = MPTVSeries.GetType("WindowPlugins.GUITVSeries.SQLCondition");
Type sqlConditionTypeEnumType = MPTVSeries.GetType("WindowPlugins.GUITVSeries.SQLConditionType");
Type dbEpisode = MPTVSeries.GetType("WindowPlugins.GUITVSeries.DBEpisode");
// SQLCondition sql = new SQLCondition();
object sql = Activator.CreateInstance(sqlConditionType);
// sql.Add(new DBEpisode(), DBEpisode.cFilename, filename, SQLConditionType.Equal);
sqlConditionType.InvokeMember("Add",
BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public,
null,
sql,
new object[] {
Activator.CreateInstance(dbEpisode),
dbEpisode.GetField("cFilename"),
filename,
sqlConditionTypeEnumType.GetField("Equal")
});
but this throws an exception with the message
The method "WindowPlugins.GUITVSeries.SQLCondition.Add"
could not be found.
My guess is that I am doing something wrong with the parameters, but as I am totally new to reflection I can't get my head around it.
Someone please help ;-)
You are going too fast. Get sqlConditionType.GetMethod() working first to get a MethodInfo so you can be sure this is not a method overload resolution problem. The arguments you pass are smelly, particularly filename and sqlConditionTypeEnumType.GetField("Equal").
I am trying to develop an NUnit addin that dynamically adds test methods to a suite from an object that contains a list of Action delegates. The problem is that NUnit appears to be leaning heavily on reflection to get the job done. Consequently, it looks like there's no simple way to add my Actions directly to the suite.
I must, instead, add MethodInfo objects. This would normally work, but the Action delegates are anonymous, so I would have to build the types and methods to accomplish this. I need to find an easier way to do this, without resorting to using Emit. Does anyone know how to easily create MethodInfo instances from Action delegates?
Have you tried Action's Method property? I mean something like:
MethodInfo GetMI(Action a)
{
return a.Method;
}
You don't need to "create" a MethodInfo, you can just retrieve it from the delegate :
Action action = () => Console.WriteLine("Hello world !");
MethodInfo method = action.Method
MethodInvoker CvtActionToMI(Action d)
{
MethodInvoker converted = delegate { d(); };
return converted;
}
Sorry, not what you wanted.
Note that all delegates are multicast, so there isn't guaranteed to be a unique MethodInfo. This will get you all of them:
MethodInfo[] CvtActionToMIArray(Action d)
{
if (d == null) return new MethodInfo[0];
Delegate[] targets = d.GetInvocationList();
MethodInfo[] converted = new MethodInfo[targets.Length];
for( int i = 0; i < targets.Length; ++i ) converted[i] = targets[i].Method;
return converted;
}
You're losing the information about the target objects though (uncurrying the delegate), so I don't expect NUnit to be able to successfully call anything afterwards.
I've run into another problem using C# 4.0 with optional parameters.
How do I invoke a function (or rather a constructor, I have the ConstructorInfo object) for which I know it doesn't require any parameters?
Here is the code I use now:
type.GetParameterlessConstructor()
.Invoke(BindingFlags.OptionalParamBinding |
BindingFlags.InvokeMethod |
BindingFlags.CreateInstance,
null,
new object[0],
CultureInfo.InvariantCulture);
(I've just tried with different BindingFlags).
GetParameterlessConstructor is a custom extension method I wrote for Type.
According to MSDN, to use the default parameter you should pass Type.Missing.
If your constructor has three optional arguments then instead of passing an empty object array you'd pass a three element object array where each element's value is Type.Missing, e.g.
type.GetParameterlessConstructor()
.Invoke(BindingFlags.OptionalParamBinding |
BindingFlags.InvokeMethod |
BindingFlags.CreateInstance,
null,
new object[] { Type.Missing, Type.Missing, Type.Missing },
CultureInfo.InvariantCulture);
Optional parameters are denoted by an ordinary attribute and are handled by the compiler.
They have no effect (other than a metadata flag) on the IL, and are not directly supported by reflection (except for the IsOptional and DefaultValue properties).
If you want to use optional parameters with reflection, you'll need to manually pass their default values.
I'll just add some code... because. The code isn't pleasent, I agree, but it is fairly straight forward. Hopefully this will help someone who stumbles accross this. It is tested, though probably not as well as you would want in a production environment:
Calling method methodName on object obj with arguments args:
public Tuple<bool, object> Evaluate(IScopeContext c, object obj, string methodName, object[] args)
{
// Get the type of the object
var t = obj.GetType();
var argListTypes = args.Select(a => a.GetType()).ToArray();
var funcs = (from m in t.GetMethods()
where m.Name == methodName
where m.ArgumentListMatches(argListTypes)
select m).ToArray();
if (funcs.Length != 1)
return new Tuple<bool, object>(false, null);
// And invoke the method and see what we can get back.
// Optional arguments means we have to fill things in.
var method = funcs[0];
object[] allArgs = args;
if (method.GetParameters().Length != args.Length)
{
var defaultArgs = method.GetParameters().Skip(args.Length)
.Select(a => a.HasDefaultValue ? a.DefaultValue : null);
allArgs = args.Concat(defaultArgs).ToArray();
}
var r = funcs[0].Invoke(obj, allArgs);
return new Tuple<bool, object>(true, r);
}
And the function ArgumentListMatches is below, which basically takes the place of the logic probably found in GetMethod:
public static bool ArgumentListMatches(this MethodInfo m, Type[] args)
{
// If there are less arguments, then it just doesn't matter.
var pInfo = m.GetParameters();
if (pInfo.Length < args.Length)
return false;
// Now, check compatibility of the first set of arguments.
var commonArgs = args.Zip(pInfo, (margs, pinfo) => Tuple.Create(margs, pinfo.ParameterType));
if (commonArgs.Where(t => !t.Item1.IsAssignableFrom(t.Item2)).Any())
return false;
// And make sure the last set of arguments are actually default!
return pInfo.Skip(args.Length).All(p => p.IsOptional);
}
Lots of LINQ, and this has not been performance tested!
Also, this will not handle generic function or method calls. That makes this significantly more ugly (as in repeated GetMethod calls).
All questions disappear as you see your code decompiled:
c#:
public MyClass([Optional, DefaultParameterValue("")]string myOptArg)
msil:
.method public hidebysig specialname rtspecialname instance void .ctor([opt]string myOptArg) cil managed
As you see, optional parameter is a real separate entity that is decorated with specific attributes and has to be respected accordingly when invoking via reflection, as described earlier.
With the opensource framework ImpromptuInterface as of version 4 you can use the DLR in C# 4.0 to invoke constructors in a very late bound way and it's totally aware of constructors with named/optional arguments, this runs 4 times faster than Activator.CreateInstance(Type type, params object[] args) and you don't have to reflect the default values.
using ImpromptuInterface;
using ImpromptuInterface.InvokeExt;
...
//if all optional and you don't want to call any
Impromptu.InvokeConstructor(type)
or
//If you want to call one parameter and need to name it
Impromptu.InvokeConstructor(type, CultureInfo.InvariantCulture.WithArgumentName("culture"))
I know this is an old thread but just want to add this.
If you're not sure how many parameters exist for the method, you can do this dynamically instead:
var method = obj.GetType().GetMethod("methodName");
int? parameters = method?.GetParameters().Length;
var data = method?.Invoke(prop, (object?[]?)(parameters.HasValue ? Enumerable.Repeat(Type.Missing, parameters.Value).ToArray() : Array.Empty<object>()));
Hope this helps.
Sorry for the poor explaination of the problem
Totally rewriting question
I have the following method:
public TReturn FindCached<TSearch, TReturn>(Func<TSearch, TReturn> searchMethod)
where TSearch : ISearchSpecification
where TReturn : class
{
SearchSpecification spec = new GetConcreteSearchSpecification<TSearch>();
//insert magic here to get an attribute from the method on
//the spec class that searchMethod invokes on the line below
return searchMethod(spec);
}
So I have a delegate (searchMethod) and an object (spec) that I want to invoke the delegate on. I want to inspect the object (spec) to find a custom attribute on the method that searchMethod will call when invoked.
Hope this is clearer.
Thanks
Assuming you meant searchMethod to be a variable of type Func<TSearch, TReturn> and mySearchSpec as some implementation of ISearchSpecification<TSearch>, then you are basically asking how to get attributes on a class.
For this, use something like:
object[] attrs = typeof(mySearchSpec).GetCustomAttributes(false);
Assuming that the mySearchSpec type is public, otherwise you may need a different overload for GetCustomAttributes
Addendum:
Based on your revised question, to get the attributes on a method on the actual type of spec used:
Type t = spec.GetType();
MethodInfo m = t.GetMethod("nameOfMethodToBeCalledHere");
object[] attrs = m.GetCustomAttributes(false);
Again, note that you may need overloads for GetMethod or GetCustomAttributes depending on the implementation of the actual class.
Note:
It does seem however like you might be asking for the method called in return searchMethod(spec);, but that is searchMethod and not some method on spec at all.
If you want attributes on searchMethod (nothing to do with spec):
MethodInfo m = searchMethod.Method;
object[] attrs = m.GetCustomAttributes(false);
I think that now covers all permutations of meaning...
This is quite a confusing question, let's see if I have it right:
You have a lambda function (which you describe as a delegate) called searchMethod.
You have a factory-pattern generated object called spec
So you have a method somewhere like this:
[MyCustomAttribute]
public RetClass MyMethod( SearchSpecification input ) {
return input.GetRetClass();
}
And you call this method with:
var result = FindCached( MyMethod );
And in FindCached you want to find MyCustomAttribute - in that case #jerryjvl's answer is right.
Your problem is that you could also do:
var result = FindCached( x => x.GetRetClass() );
I'm not sure from your description whether it's an attribute on the x.GetRetClass() that you actually want. In this case you need to take the lambda apart using expressions, but I wouldn't recommend it - a more complex lambda declaration will result in an anonymous delegate, which is a black-box when you try to parse it at run time.
Instead, as you're using reflection anyway, it might be easier to pass the name of the method that you want instead of the delegate reference:
var result = FindCached( "GetRetClass" );
I ran into a similar situation, jerryjvl's answer explained exactly what I wanted.
I wanted to create a generic profiling method, where I could time how long some method took to run, and retrieve the name of the method using reflection for logging purposes.
The MethodInfo was the key.
Where I have a method like:
public static bool TimeMethod(Func<bool> someMethod)
And then later I want to dynamically get it's name or some attributes off it.
MethodInfo m = someMethod.Method;
object[] attrs = m.GetCustomAttributes(typeof(MonitoringDescriptionAttribute), true);
string name = m.Name;
Cheers