C# - Investigating "Method' information using Reflection? - c#

My intention is to investigate the "Methods" of a Type using reflection in order to verify the following :
The Methods should be instance methods and public.
Takes the parameter "params" and void in nature.
The Method does not makes recursive call.
I started as :
static void ProcessMethodInfo(Type t)
{
MethodInfo[] info = t.GetMethods();
foreach (MethodInfo mi in info)
{
// How to check the conditions here ?
}
}
But I don't know how to proceed further. Help is needed.

Well, if by 3 you mean the method under inspection should be non-recursive; then that is a pain - you'd need to parse the IL. But for the others;
Type type = ...
var qry = from method in type.GetMethods(
BindingFlags.Instance | BindingFlags.Public)
where method.ReturnType == typeof(void)
let parameters = method.GetParameters()
where parameters.Length == 1
&& parameters[0].ParameterType.IsArray
&& Attribute.IsDefined(parameters[0], typeof(ParamArrayAttribute))
select method;
foreach (var method in qry)
{
Console.WriteLine(method.Name);
}

mi.IsStatic, etc - read help
Determining if a parameter uses "params" using reflection in C#?
http://www.codeproject.com/KB/cs/sdilreader.aspx
ALL: use google ;)

I don't think you'll be able to detect item 3 using reflection.

Check the following members of the MethodInfo class:
IsPublic
IsStatic
ReturnType
GetParameters() method
In order to be able to check whether the method is recursive, I think you'll need something more then just simple reflection.

Related

Issues with calling a static method through a string using reflection

I am making an app which is interfaced with at the command line by typing commands that then call corresponding methods. The thing is, some of these methods are asynchronous, and thus, according to what I've heard, should return Task instead of void, even when their return value is not used (async is not necessary for the program I am making, however a library I am using in some of the methods is asynchronous).
Because of this, I can't use a dictionary of delegates (as far as I know), as they would be different types, so I have tried using reflection.
MethodInfo command = MethodBase.GetCurrentMethod()
.DeclaringType
.GetMethod(_commands[args[0]]);
command.Invoke(null, new string[][] { args });
The above snippet is intended to get a static method by its name and then call it with argument string[] args.
According to the documentation I'm looking at, alongside other StackOverflow answers, the first argument should be null if the method being called is static, however I get a NullReferenceException anyway. Why is this, and how do I fix it?
Well, GetMethod can well return null or some non static method
MethodInfo command = MethodBase
.GetCurrentMethod()
.DeclaringType
.GetMethod(_commands[args[0]]);
So we have to check if command is valid one; since args[0] is used in finding the method, I guess it should be removed from parameters (Skip(1)):
if (command != null && command.IsStatic)
command.Invoke(null, args.Skip(1).Cast<Object>().ToArray());
please, note, that you have to do more validation if method can be overload (i.e. we have several methods with the same name), something like this:
MethodInfo command = MethodBase
.GetCurrentMethod()
.DeclaringType
.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(m => m.Name == _commands[args[0]])
.Where(m => m.GetParameters().Length == args.Length - 1) // - 1 for Skip(1)
.FirstOrDefault();
You must check that the command is not null.
If you don't want to handle the case to only call it if not null, you can simply write:
command?.Invoke(null, new string[] { args });
Thus if the method does not exist, GetCurrentMethod returns null and nothing is done.
But if you want to manage the case you need to use a test and for example show a system message.
You should also hardness the code by checking if args is noty empty too.
And you should also add some bindings flags to the search.
if (args.Length == 0)
{
Console.WriteLine("No command provided.");
return;
}
string commandName = _commands[args[0]];
// You can remove non public or public depending on the nature of your methods
var flags = var flags = BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public;
var command = MethodBase.GetCurrentMethod().DeclaringType.GetMethod(commandName, flags);
if (command == null)
{
Console.WriteLine("Command not found: " + commandName);
Console.WriteLine("Allowed commands are:"
Console.WriteLine("- ...");
Console.WriteLine("- ...");
return;
}
command.Invoke(null, new string[] { args });
I removed the jagged array [][] as seen and suggested by #DmitryBychenko in case of it was a mistake (it should be) that causes the error in the executed method if it exists.
Here a some example of advanced command line arguments parsing:
Parsing command-line options in C#
Best way to parse command line arguments in C#?
https://codereview.stackexchange.com/questions/369/parsing-console-application-arguments
https://github.com/mykeels/CommandLineParser
https://github.com/commandlineparser/commandline
https://www.codeproject.com/Articles/19869/Powerful-and-simple-command-line-parsing-in-C

how to call a private method from dll? [duplicate]

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

How do you call a generic method with out parameters by reflection?

Suppose I have a class like this, containing a generic method with an out parameter:
public class C
{
public static void M<T>(IEnumerable<T> sequence, out T result)
{
Console.WriteLine("Test");
result = default(T);
}
}
From reading the answers to a couple of other questions (How to use reflection to call generic Method? and Reflection on a static overloaded method using an out parameter), I thought I might be able to invoke the method via reflection as follows:
// get the method
var types = new[] { typeof(IEnumerable<int>), typeof(int).MakeByRefType() };
MethodInfo mi = typeof(C).GetMethod(
"M", BindingFlags.Static, Type.DefaultBinder, types, null);
// convert it to a generic method
MethodInfo generic = mi.MakeGenericMethod(new[] { typeof(int) });
// call it
var parameters = new object[] { new[] { 1 }, null };
generic.Invoke(null, parameters);
But mi is coming back null. I've tried using object instead of int in the types array but that doesn't work either.
How can I specify the types (needed for the out parameter) for a generic method before the call to MakeGenericMethod?
This will let you call the method:
MethodInfo mi = typeof(C).GetMethod("M");
MethodInfo generic = mi.MakeGenericMethod(new[] { typeof(int) });
var parameters = new object[] { new[]{1},null};
generic.Invoke(null, parameters);
And to get the out parameter:
Console.WriteLine((int)parameters[1]); //will get you 0(default(int)).
I'm still interested to know what the syntax is for specifying an array of template types, or if it's not possible
I don't think it's possible to pass that kind of detailed type specification to GetMethod[s]. I think if you have a number of such Ms to look through, you have to get them all and then filter by the various properties of the MethodInfos and contained objects, eg as much of this as is necessary in your particular case:
var myMethodM =
// Get all the M methods
from mi in typeof(C).GetMethods()
where mi.Name == "M"
// that are generic with one type parameter
where mi.IsGenericMethod
where mi.GetGenericArguments().Length == 1
let methodTypeParameter = mi.GetGenericArguments()[0]
// that have two formal parameters
let ps = mi.GetParameters()
where ps.Length == 2
// the first of which is IEnumerable<the method type parameter>
where ps[0].ParameterType.IsGenericType
where ps[0].ParameterType.GetGenericTypeDefinition() == typeof(IEnumerable<>)
where ps[0].ParameterType.GetGenericArguments()[0] == methodTypeParameter
// the second of which is ref <the method type parameter>
where ps[1].ParameterType.IsByRef
where ps[1].ParameterType.GetElementType() == methodTypeParameter
select mi;
You've passed parameters that will find M<T>(IEnumerable<int>, ref int).
You need to find M(IEnumerable<T>, ref T) (the distinction between ref and out exists only in the C# language; reflection only has ref).
I'm not sure how to pass that; you may need to loop through all methods to find it.
On an unrelated note, you need to pass more BindingFlags:
BindingFlags.Public | BindingFlags.Static
This is a well known-problem; to find the method, you need to know its type parameter, but you can't know its type parameter without knowing the method first...
An obvious but inelegant solution is to loop through all methods until you find the right one.
Another option is to take advantage of the Linq Expression API:
public static MethodInfo GetMethod(Expression<Action> expr)
{
var methodCall = expr.Body as MethodCallExpression;
if (methodCall == null)
throw new ArgumentException("Expression body must be a method call expression");
return methodCall.Method;
}
...
int dummy;
MethodInfo mi = GetMethod(() => C.M<int>(null, out dummy));

Get generic argument type and value supplied to a generic method

How do you get the argument value supplied to a closed/constructed generic method?
It's been a while since I haven't touched Reflection. All this used to be at the back of my, umm, whatever.
class Program
{
static void Main(string[] args)
{
new ConcreteFoo().GenericMethod<int>(5);
Console.ReadKey();
}
}
class ConcreteFoo
{
public void GenericMethod<Q>(Q q)
{
var method = MethodInfo.GetCurrentMethod();
var parameters = method.GetParameters();
if (parameters.Length > 0)
foreach (var p in parameters)
Console.WriteLine("Type: {0}", p.ParameterType);
// That still prints Q as the type.
// I've tried GetGenericArguments as well. No luck.
// I want to know:
// 1) The closed type, i.e. the actual generic argument supplied by the caller; and
// 2) The value of that argument
}
public void GenericMethodWithNoGenericParameters<Q>()
{
// Same here
}
}
class GenericFoo<T>
{
public void NonGenericMethod(T t) { /* And here*/ }
public void GenericMethod<Q>(Q q) { /* And here */ }
}
UPDATE
This question is absurd and hence closed by the asker. He wishes to retain it just to show his children how stupid daddy was, if they ever turned out to be C# programmers.
The short answer is typeof(Q).
The long answer (which tries to explain why you can't enumerate these types and you must write them specifically) goes like this:
Each generic method (which is more generic than it's declaring class) has corresponding, distinct MethodInfo instances for all of its (ever) touched particularizations and another MethodInfo for the "template"/open method.
You could use this to obtain what you want:
class ConcreteFoo {
public void GenericMethod<Q>(Q q) {
var method = MethodInfo.GetCurrentMethod();
var closedMethod = method.MakeGenericMethod(typeof(Q));
// etc
}
}
Why is that ?
It's because none of the "enumerating operations" in reflection return MethodInfo instances that refer to closed particularizations.
If you enumerate the static methods declared by ConcreteFoo like so:
var atTime1 = typeof(ConcreteFoo).GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
ConcreteFoo.GenericMethod( true );
var atTime2 = typeof(ConcreteFoo).GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
you will get identical results.
As far as GenericMethod and it's entourage of particularizations are concerned, you will get only the reflection object associated with GenericMethod (open variant).
atTime2 will not contain an extra MethodInfo referring to the freshly jitted GenericMethod< bool >.
But that not's really a bad thing, now is it ?
GetMethods() should return consistent results and not have its results vary in time.
The algebra of generic methods is actually quite nice when it comes to it's "navigation" operations:
All open MethodInfos have IsGenericMethod = true and IsGenericMethodDefinition = true
All closed MethodInfos have IsGenericMethod = true and IsGenericMethodDefinition = false
By calling .GetGenericMethodDefinition() on a closed MethodInfo you get the open one
By calling .MakeGenericType(params Type[] types) on an open MethodInfo you get whatever closed one you want (without being syntactically aware of what those types are and with the possibility of receiving an exception for not respecting the where clauses)
The same goes for the reflection operations that come from the current thread's perspective (rather than from that of the assemblies and types):
MethodBase MethodInfo.GetCurrentMethod()
and
StackTrace trace = new StackTrace();
IEnumerable<MethodBase> methods = from frame in trace.GetFrames()
select frame.GetMethod();
never return the actual closed variants of generic methods (if any)
that are actually on the top, or throughout the current call stack.
In a way your question is not absurd, because, while in the case of GetCurrentMethod
you could easily replace it with GetCurrentMethod plus MakeGenericMethod plus the syntactically available typeof(Whatever), you can't say that about your callers.
So.. for non-generic methods you can always look at your stack and know precisely what are those methods' parameter types. The methods that invoked each other and eventually yours got invoked... But for generic ones (which are really truly closed, for I repeat it is illogical to think that a generic method that runs and calls another and was called by someone else (etc) is an open one) you can't find out the types of the parameters just like you can't learn the values of any such methods' local variables (which are deterministic but it would be a great flaw in performance to make that a possibility).

Instantiate type with string parameter to constructor dynamically

I have the following code:
if (FileType == typeof(ScanUploadFile))
{
files.Add(new ScanUploadFile(filePath));
}
if (FileType == typeof(FaxFile))
{
files.Add(new FaxFile(filePath));
}
if (FileType == typeof(BulkScanFile))
{
files.Add(new BulkScanFile(filePath));
}
if (FileType == typeof(SpecialCategoryFile))
{
files.Add(new SpecialCategoryFile(filePath));
}
How can I write it without the IF statement?
Since you are only interested in the constructor, you could use:
Activator.CreateInstance(FileType, new string[] {filePath});
Activator is defined in the System library.
Use GetConstructors method of the Type object and chose the one with single parameter of type string, then invoke it.
Like so:
private ConstructorInfo GetStringConstructor(Type type)
{
return (from ctor in type.GetConstructors()
let pars = ctor.GetParameters()
where pars.Length == 1 && pars[0].ParameterType == typeof(string)
select ctor).FirstOrDefault();
}
Use it like so:
var ctor = GetStringConstructor(typeof(Test));
if (ctor != null)
files.Add(ctor.Invoke(new string[] {filePath}));
I made a separate method for extracting the constructor, but if you only intend to use it for actually creating an instance, you can refactor it all in one method that takes string and Type parameters. Pay some attention to proper error handling though.
However, I would consider Factory method pattern here instead of just diving in reflection right away. I can't know if it better suits your needs, but it seems like it probably does.
EDIT: I admit that the CreateInstance is nicer, but my method has the advantage of more control and better error handling.

Categories