Call dynamic method from string - c#

I'm trying to call a method from a dynamic without knowing its name. I have difficulties to explain this in english so there's the code:
public void CallMethod(dynamic d, string n)
{
// Here I want to call the method named n in the dynamic d
}
I want something like:d.n() but with n replaced by the string.
I want this :
Type thisType = this.GetType();
MethodInfo theMethod = thisType.GetMethod(TheCommandString);
theMethod.Invoke(this, userParameters);
but with dynamic.
If you need the context to help you: I'm make an application that's support "mods", you put DLLs in the mod folder and it loads it and execute it. It works with dynamic (I have a dictionnary like this : Dictionnary<string, dynamic> instances;). I want the application to get the methods name from the library (with instances["topkek"].GetMethods();, I've already made this method) but then call the method with the string it returns. I don't know if what I said mean something (I'm french :/ )...
I'm using VS 2013 Express with the .Net framework 4.5, if you need more information to help me ask me.

you can write your method as follows -
public void CallMethod(dynamic d, string n)
{
d.GetType().GetMethod(n).Invoke(d, null);
}

If all methods are void, this could work. Otherwise you need to change it a bit.
public void CallMethod(string className, string methodName)
{
object dynamicObject;
// Here I want to call the method named n in the dynamic d
string objectClass = "yourNamespace.yourFolder." + className;
Type objectType = Type.GetType(objectClass);
if (objectType == null)
{
// Handle here unknown dynamic objects
}
else
{
// Call here the desired method
dynamicObject = Activator.CreateInstance(objectType);
System.Reflection.MethodInfo method = objectType.GetMethod(methodName);
if (method == null)
{
// Handle here unknown method for the known dynamic object
}
else
{
object[] parameters = new object[] { }; // No parameters
method.Invoke(dynamicObject, parameters);
}
}
}

I want to add another approach as solution:
In your case, the caller (developer of the mod) knows the method to call. Thus, this might helpful:
// In the main application:
public dynamic PerformMethodCall(dynamic obj, Func<dynamic, dynamic> method)
{
return method(obj);
{
// In a mod:
mainProgram.PerformMethodCall(myDynamicObj, n => n.myDynamicMethod());
// In another mod:
mainProgram.PerformMethodCall(myDynamicObj, n => n.anotherMethod());
This is a further development of the idea of Yuval Itzchakov in his commentary. He had suggested using a delegate.

Related

How to check method exists in C# with certain particular signature?

I want to check if the method for certain parameters is implemented. In this scenario, I have for example these method overloads:
public class Transformations
{
public string TransformFrom(string s) { return s;}
public string TransformFrom(int i) { return "00" + i.ToString();}
public string TransformFrom(DateTime dt) { return
DateTime.ToString("MM/dd/yyyy HH:mm:ss.fff");}
}
Suppose I have decimal like:
object obj = 1M;
If I now call TransformFrom(obj), I get an exception.
Other part of my program returns unfortunately only objects, which really are concrete types like int or datetime. And I want to transform some of these objects to string so that those can be written to the log. So this is a runtime problem. Also I want that my Transformations-class is general enough to be used in other programs too, so there can be objects of any type.
Is there fast way to find out that this method overload does not exist?
Either way you are currently going to get a compile time error, even if there was an overload that accepted a decimal. You can approach this one of 2 ways depending on your needs:
To resolve this at compile time you have to cast to the correct type.
object obj = 1;
var objAsInt = (int) obj;
var result = transformationInstance.TransformFrom(objAsInt);
If there is no proper overload you will get a compile time error and you can resolve this at design time.
To resolve this at runtime use reflection to figure out if there is an overload of the type and if there is pass the instance.
object obj = 1;
var underlyingType = obj.GetType();
var method = typeof(Transformations).GetMethod("TransformFrom", new Type[] { underlyingType });
if(method != null)
{
var result = method.Invoke(transformationInstance, new []{obj});
}
It is possible to find out whether a given overload exists using reflection:
public static bool HasOverloadForArgument(Type targetType, string methodName, object arg)
{
var methodInfo = targetType.GetMethod(name: methodName, types: new[] { arg.GetType() });
return methodInfo != null;
}
Live sample
I'm not sure what is the whole idea here as there won't be much you can do when the transformation is not available during runtime.
Maybe, you'd just be best off using dynamic to avoid all the reflection stuff and caching required otherwise, e.g.
var boxedInt = (object)1;
var boxedFloat = (object)1f;
dynamic dynamicInt = boxedInt;
dynamic dynamicFloat = boxedFloat;
var intResult = new Transformations().TransformFrom(dynamicInt); // works
var floatResult = new Transformations().TransformFrom(dynamicFloat); // throws binder exception

Invoke method in stored object

I'm a bit confused atm and i dont think it could be this hard as then i must be doing something wrong. What i am trying to do now for the past 2 days is to access a method inside an object that is stored in an List and i just cant get at it. In my mind it should just be to get the object back to its originated type and invoke the method but i just cant do it.
I been reading alot about Type, Generics and reflection but it cant get anyting to work so i am obviusly doing it all wrong and i need help finding the light!
Heres the latest code i have tried
Object customer = Hotel.Main.Manager.GetMainList(x);
Type frsttype = customer.GetType();
MethodInfo method = frsttype.GetMethod("GetCustomerSpecificData");
MethodInfo generic = method.MakeGenericMethod(frsttype);
String str = generic.Invoke(method);
What i am trying to reach is this method inside the object:
public override string GetCustomerSpecificData()
{
string strout = string.Format("{0,-5}{1,26}{2,28}{3,28}\a", ID, Name, Age, Gender);
string strInfo = Extra;
strout += (string.IsNullOrEmpty(strInfo) ? string.Empty : strInfo);
if (m_specialoffer)
{
strout += string.Format("\nSpecial Offer");
}
if (IsRegularCustomer)
{
strout += (IsDangerus ? "\nIs a regular customer " : "\nIs not a regular customer.");
}
strout += Environment.NewLine + PaymentInfo();
strout += (m_CarPark ? "\nHas car parked in garage." : "\nDoes not have car parked in garage.");
return strout;
}
I hope someone can point me in the correct direction as i dont think i am getting anywhere with this one :/
Any help and hints will be greatly appreciated!!! All will be upvoted for replies!
Regards
There a few things here that you need to do, firstly lets look at the codeyou posted
First question you need t ask youself is Do I need to use reflection, can I instead use interfaces or return a type that I know?
Do you have control of the GetMainList(x)? If so cant you change it so it returns something more useful other then a object?
Object customer = Hotel.Main.Manager.GetMainList(x);
Can you cast to anything?
Secondly your target method is no a generic method so the line below is not going to work.
MethodInfo generic = method.MakeGenericMethod(frsttype);
You are also invoking the method incorrectly you Invoke has two arguments the first one is the target object you wish to invoke the method against and the parameters you can pass into it.
Invoke(object obj, object[] parameters)
To invoke you method you need to the following.
Object customer = Hotel.Main.Manager.GetMainList(x);
Type frsttype = customer.GetType();
MethodInfo method = frsttype.GetMethod("GetCustomerSpecificData");
String str = method.Invoke(customer, null) as string;
There is some great questions and community wikis on stackoverflow and of course there is many tutorials and example in the MSDN library.
A nice tutorial for reflection in .net can be found below.
Reflection in C# Tutorial
i mean you can easy invoke it :
Type myType =customer.GetType();
MethodInfo method = typeof(customer).GetMethod("GetCustomerSpecificData");
MethodInfo generic = method.MakeGenericMethod(myType);
var res= generic.Invoke(this, null);
Closest to what you currently have this could work without relying on reflection.
Object customer = Hotel.Main.Manager.GetMainList(x);
string result="";
var custObj = customer as Customer;
if (custObj !=null)
{
result = custObj.GetCustomerSpecificData();
}
var specialcustObj = customer as SpecialCustomer;
if (specialcustObj !=null)
{
result = specialcustObj.GetCustomerSpecificData();
}
/* etc */
Or, If you can change the implementation of the different types in the List have an interface (or alternative an (abstract) base class.
/* alternatively name it ISpecificData if you want adhere common used standards */
public interface SpecificData
{
string GetCustomerSpecificData();
}
and for your Customer and other classes that can be in the list :
public class Customer:SpecificData
{
/* rest of implemementastion stays the same */
}
Your code to Get a customer would go like this, and will work for every object in the list that implemented the interface.
Object customer = Hotel.Main.Manager.GetMainList(x);
string result="";
var interfaceObj = customer as SpecificData;
if (interfaceObj != null)
{
result = interfaceObj.GetCustomerSpecificData();
}
When you know that only a specific interface will be in the list you can use the generic list to only hold object for that specific type:
mainlist = new List<SpecificData>();
and you can adapt GetMainList to only return the interface SpecificData

Dynamic invoke of a method using named parameters

We're currently using .NET 3.5 and part of our application uses dynamic invocation (using MethodBase.Invoke)
I am wondering if it is possible to mix in Named Parameters (in .NET 4) with dynamic invocation, to perform something similar to:
// Dictionary that holds parameter name --> object mapping
var parameters = new Dictionary<string, object>();
// Add parameters ....
// Invoke where each parameter will match the one from the method signature.
methodInfo.Invoke(obj, parameters);
Is there any API that allows this option out of the box? If not, is it possible to develop some solution to perform this?
EDIT:
Rethinking of this problem, it sounds similar to how the compiler may actually need to match method calls based on argument lists. Perhaps there's some Compiler API (or the new Roslyn project) that allows doing just this easily? (without coding it myself which may be prone to errors).
You can use code like this:
public static class ReflectionExtensions {
public static object InvokeWithNamedParameters(this MethodBase self, object obj, IDictionary<string, object> namedParameters) {
return self.Invoke(obj, MapParameters(self, namedParameters));
}
public static object[] MapParameters(MethodBase method, IDictionary<string, object> namedParameters)
{
string[] paramNames = method.GetParameters().Select(p => p.Name).ToArray();
object[] parameters = new object[paramNames.Length];
for (int i = 0; i < parameters.Length; ++i)
{
parameters[i] = Type.Missing;
}
foreach (var item in namedParameters)
{
var paramName = item.Key;
var paramIndex = Array.IndexOf(paramNames, paramName);
if (paramIndex >= 0)
{
parameters[paramIndex] = item.Value;
}
}
return parameters;
}
}
And then call it like this:
var parameters = new Dictionary<string, object>();
// Add parameters ...
methodInfo.InvokeWithNamedParameters(obj, parameters);
you can get your paramter names with the help of this article How can you get the names of method parameters? and then you can reorder them to invoke them as described here Reflection: How to Invoke Method with parameters
With .net4, I have an opensource framework ImpromptuInterface (found in nuget) that makes it easy to use the DLR apis for late invocation including named/optional parameters.
var result = Impromptu.InvokeMember(target, "MyMethod", parameters.Select(pair=> InvokeArg.Create(pair.Key, pair.Value)).Cast<object>().ToArray());

MethodInfo.Invoke parameter order

I'm trying to invoke a method using reflection.
Something like this:
method.Invoke(instance, propValues.ToArray())
The problem is that there isn't a way to ensure the array of parameters is in the right order. Is there a way to specific which values goes on which parameter by name? Or do I really have to make a custom binder? If so, can anyone guide me in the right direction?
Is there a way to specific which values goes on which parameter by name?
Well, you specify them in parameter order. So if you want to map specific values to specific names, you should fetch the parameter list with method.GetParameters and map them that way. For example, if you had a Dictionary<string, object> with the parameters:
var arguments = method.GetParameters()
.Select(p => dictionary[p.Name])
.ToArray();
method.Invoke(instance, arguments);
EDIT: This answer focuses on parameter types not the parameter names. If the code is obfuscated (or having different param names) then it will be difficult to map the solution that Jon Skeet has provided.
Anyway, I had been playing with this a lot.... This is what works best for me (without knowing param names) :
public object CallMethod(string method, params object[] args)
{
object result = null;
// lines below answers your question, you must determine the types of
// your parameters so that the exact method is invoked. That is a must!
Type[] types = new Type[args.Length];
for (int i = 0; i < types.Length; i++)
{
if (args[i] != null)
types[i] = args[i].GetType();
}
MethodInfo _method = this.GetType().GetMethod(method, types);
if (_method != null)
{
try
{
_method.Invoke(this, args);
}
catch (Exception ex)
{
// instead of throwing exception, you can do some work to return your special return value
throw ex;
}
}
return result;
}
so, you can call the above function:
object o = CallMethod("MyMethodName", 10, "hello", 'a');
The above call will should be able to invoke this method with matching signature:
public int MyMethodName(int a, string b, char c) {
return 1000;
}
Please note that he above example is in the scope of 'this'

Call a function with unknown type and number of parameters in C#

I am writing a library in C# and I have to call some methods defined by other programmers in their classes, so I do not priory know about types and number of parameters. For example,
Class exampleClass{
void method1(int param1, double param2){...}
bool method2(){...}
object method3(string param1){....}
}
In my program, I want to call these methods. As I don't know their parameters and return types, I cannot use "delegate"s (which have known types and parameters) but in run-time, I can use, for example, reflection to extract methods and their parameters ("MethodInfo"s) from the class but how to use this information to call the methods? (assuming that I can generate the proper values to be used as the parameters of methods).
Thanks
PS: I know "params object []" approach but it will force programmers to use "params" objects instead of defining their usual parameters in their methods. So, I don't want to use this approach.
You can use reflection to get all the information you need about a method.
For example once you have the MethodInfo you can get the ReturnType
Type MyType = Type.GetType("System.Reflection.FieldInfo");
MethodInfo Mymethodinfo = MyType.GetMethod("GetValue");
Console.Write ("\n" + MyType.FullName + "." + Mymethodinfo.Name);
Console.Write ("\nReturnType = {0}", Mymethodinfo.ReturnType);
GetParameters will tell you the parameters:
Type delegateType = typeof(MainClass).GetEvent("ev").EventHandlerType;
MethodInfo invoke = delegateType.GetMethod("Invoke");
ParameterInfo[] pars = invoke.GetParameters();
foreach (ParameterInfo p in pars)
{
Console.WriteLine(p.ParameterType);
}
Once you have this information you can use Invoke to actually call the method.
Its first argument is the "object on which to invoke the method".
Its second argument is the argument list for said method.
The code I'm providing works with the ExampleClass you provided, but in no way is it a complete solution. You need to take generics, ref, out params, and probably a whole lot of other things into consideration.
public void CallAllMethods(object instance)
{
foreach (MethodInfo method in instance.GetType().GetMethods())
{
if (method.IsGenericMethod || method.DeclaringType == typeof(object))
{
// skipping, System.Object method or a generic method
continue;
}
var defaultParamValues = method.GetParameters().Select(p => GetDefaultValue(p.ParameterType)).ToArray();
Console.WriteLine("Invoking {0} with param values {1}", method.Name, string.Join(", ", defaultParamValues));
object retVal = method.Invoke(instance, defaultParamValues);
if (method.ReturnType != typeof(void))
{
Console.WriteLine(" and returned a value of {0}", retVal);
}
}
}
public static object GetDefaultValue(Type type)
{
return type.IsValueType ? Activator.CreateInstance(type) : null;
}

Categories

Resources