Invoking methods with optional parameters through reflection - c#

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.

Related

Method created during runtime changes the parameter order of another method call depending on how it is run

I implement interfaces during runtime using Reflection.Emit and create their defined methods.
Example definition of a method in the interface:
IFoo DoSomething(IBar bar, string name);
To create the methods I do the following:
var args = methodInfo.GetParameters();
MethodBuilder methodBuilder = typeBuilder.DefineMethod(methodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual,
methodInfo.ReturnType, (from arg in args select arg.ParameterType).ToArray());
typeBuilder.DefineMethodOverride(methodBuilder, methodInfo);
var generator = methodBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, fieldBuilder);
generator.Emit(OpCodes.Ldtoken, methodInfo.ReturnType);
if (args.Any())
{
generator.Emit(OpCodes.Ldc_I4_S, args.Length);
generator.Emit(OpCodes.Newarr, typeof(object));
for (int i = 0; i < args.Length; i++)
{
generator.Emit(OpCodes.Dup);
generator.Emit(OpCodes.Ldc_I4_S, i);
generator.Emit(OpCodes.Ldarg_S, i + 1);
generator.Emit(OpCodes.Stelem_Ref);
}
}
else
{
generator.Emit(OpCodes.Ldc_I4_0);
}
generator.EmitCall(OpCodes.Callvirt, typeof(ISomeType).GetMethod(nameof(ISomeType.Test), new[] {typeof(Type), typeof(object[])}), null);
generator.Emit(OpCodes.Ret);
This generates me for example my DoSomething(IBar bar, string name) method of the interface.
All generated methods call the method Test() of ISomeType.
This is the method Test():
public object Test(Type type, object[] arguments)
{
//do something
}
When I run my application and call the DoSomething() method, the parameters are passed the wrong way (object[] first and Type second) to Test(), which obviously leads to an exception.
But when I run a unit test and call the DoSomething() method, the parameters are passed correctly (Type first and object[] second) to Test().
Why is there a difference in which order the parameters are passed to the Test() method depending on how it is run?
So with a lot of help of Marc Gravell in the comments I found out what to do to get this problem fixed.
First of all I had an error in the way I created my methods.
The case when a method has no arguments has to be changed from
generator.Emit(OpCodes.Ldc_I4_0);
that pushes just a 0 as Int32 onto the stack, to
MethodInfo emptyArray = typeof(Array).GetMethod(nameof(Array.Empty))?.MakeGenericMethod(typeof(object));
generator.EmitCall(OpCodes.Call, emptyArray, null);
which really pushes an empty array to the stack that will get passed as an argument to the Test() function.
To fix the problem with the wrong parameter order there are two possible solutions in my specific case:
(1) More changes to the generated IL code:
Really push the return type of the method as a Type and not a RuntimeTypeHandle:
generator.Emit(OpCodes.Ldtoken, methodInfo.ReturnType);
MethodInfo getTypeFromHandle = typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle));
generator.EmitCall(OpCodes.Call, getTypeFromHandle, null);
Cast the return type of Test() to the wanted return type of the method before returning:
generator.EmitCall(OpCodes.Callvirt, typeof(ISomeType).GetMethod(nameof(ISomeType.Test), new[] {typeof(Type), typeof(object[])}), null);
generator.Emit(OpCodes.Castclass, methodInfo.ReturnType);
generator.Emit(OpCodes.Ret);
(2) Convert Test() method to a generic method:
In case you have parameters as a Type you can convert your method to a generic method:
public T Test<T>(object[] arguments)
{
//do something
}
If you decide to do so, you will have to change some of the IL code generation as well:
Don't push return type of the method to the stack:
Remove this line:
generator.Emit(OpCodes.Ldtoken, methodInfo.ReturnType);
Change the call of Test():
MethodInfo test = typeof(ISomeType).GetMethod(nameof(ISomeType.Test), new[] { typeof(object[]) }).MakeGenericMethod(methodInfo.ReturnType);
generator.EmitCall(OpCodes.Callvirt, test, null);
generator.Emit(OpCodes.Ret);
You also don't have to cast the return value in this case because your method Test() already returns the correct type with T.
With any of those two solutions the Test() method gets call with the correct parameter order regardless of how it is called (application or unit test).
Another tip of Marc Gravell was to use Sigil to get clear error messages when your generated IL code is invalid. And no matter which of the two solutions above you are choosing I can only recommend to do so.

Method.Invoke failing with Parameter Count Mismatch

I am trying to invoke a generic method. The definition of the method is as follows:
public System.Collections.Generic.IList<T> Query<T>(string query, [string altUrl = ""])
where T : new()
This is from the SalesforceSharp library on github. I am trying to make an additional service layer over this call and am struggling to invoke it. See my code below.
public List<T> Query<T>()
{
//IList<Salesforce.Account> _returnList = null;
IList<T> _returnList = null;
Type _t = typeof(T);
SqlBuilder _sb = new SqlBuilder();
_sb.Table = _t.Name.ToString();
foreach (PropertyInfo p in _t.GetProperties()) _sb.Fields.Add(p.Name.ToString());
MethodInfo method = _Client.GetType().GetMethod("Query");
method = method.MakeGenericMethod(_t);
try
{
object[] _prms = new object[1];
_prms[0] = _sb.SQL;
_returnList = (IList<T>)method.Invoke(_Client, new object[] { _prms });
//_returnList = _Client.Query<Salesforce.Account>(_sb.SQL);
}
catch { }
return (List<T>)_returnList;
}
If I run this i get a Parameter Count Mismatch exception on the method.invoke line, but i am confused because if i bring in the two uncommented lines and execute without the generic call it is working ok. I have tried many combinations of string arrays wrapped in object arrays, strings in strings, etc but can't get it to go. I thought maybe it was treating the second parameter as mandatory? but adding another object to my _prms array didnt work either.
Please help!
Thanks,
Dom
For optional parameters that you don't want to specify a value for, you have to pass Type.Missing like this:
_returnList = (IList<T>)method.Invoke(_Client, new object[] { _sb.SQL, Type.Missing });
Quoting from this reference:
Use the Missing field for invocation through reflection to obtain the default value of a parameter
Please note also that another problem is that you are currently passing an object[] instead of just the query string.
The optional parameters are just syntactic sugars, when you don't supply an optional parameter compiler calls the method with the given default value. But in case of Reflection, you need to do it manually.
object[] _prms = new object[2];
_prms[0] = _sb.SQL;
_prms[1] = "";
_returnList = (IList<T>)method.Invoke(_Client, _prms);

Passing a Parameter Array by ref to C# DLL via Reflection

All, I have a number of C# DLLs that I want to call from my application at runtime using System.Reflection. The core code I use is something like
DLL = Assembly.LoadFrom(Path.GetFullPath(strDllName));
classType = DLL.GetType(String.Format("{0}.{0}", strNameSpace, strClassName));
if (classType != null)
{
classInstance = Activator.CreateInstance(classType);
MethodInfo methodInfo = classType.GetMethod(strMethodName);
if (methodInfo != null)
{
object result = null;
result = methodInfo.Invoke(classInstance, parameters);
return Convert.ToBoolean(result);
}
}
I would like to know how I can pass in the array of parameters to the DLL as ref so that I can extract information from what happened inside the DLL. A clear portrayal of what I want (but of course will not compile) would be
result = methodInfo.Invoke(classInstance, ref parameters);
How can I achieve this?
Changes to ref parameters are reflected in the array that you pass into MethodInfo.Invoke. You just use:
object[] parameters = ...;
result = methodInfo.Invoke(classInstance, parameters);
// Now examine parameters...
Note that if the parameter in question is a parameter array (as per your title), you need to wrap that in another level of arrayness:
object[] parameters = { new object[] { "first", "second" } };
As far as the CLR is concerned, it's just a single parameter.
If this doesn't help, please show a short but complete example - you don't need to use a separate DLL to demonstrate, just a console app with a Main method and a method being called by reflection should be fine.

C# Get Delegate (Func) implementation from concrete class via reflection?

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

How do I use reflection to invoke a private method?

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

Categories

Resources