How to do automatic type conversion for parameters when calling a method using reflection in C #?

I need to call methods for a type through reflection using C #.

At runtime, my data will consist of a dictionary containing name / value pairs. The names in the dictionary will correspond to the names of the parameters in the method that I will call. Also, at runtime, I will have an arbitrary assembly type name and method name. During development, I will not know the type and method other than that the method will accept a variable number of parameters like int, string, DateTime, bool, int [], string [], DateTime [] or bool [].

I have no problem so that I can instantiate the type using reflection and call the method. I am stuck at the point where I need to convert the string values ​​in my dictionary to the appropriate type needed by the method when called:

someMethodInfo.Invoke(instance, new [] { ... }) 

I know that I probably need to list through MethodInfo.GetParameters () and perform type conversion for each parameter. I am trying to figure out how to do this, and ideally, how to do it effectively.

My research so far has included digging into the MVC source code, as it does something similar when passing form values ​​to ActionMethod. I found ActionMethodDispatcher but uses LINQ Expressions that I am not familiar with.

I also looked at similar questions on SO, but did not find anything that answered my question.

I would welcome any pointers to a solution.

+7
source share
3 answers

Here is the code you can use to convert the parameters:

 public object ConvertSingleItem(string value, Type newType) { if (typeof(IConvertible).IsAssignableFrom(newType)) { return Convert.ChangeType(value, newType); } else { // TODO: Add custom conversion for non IConvertible types var converter = CustomConvertersFactory.GetConverter(newType); return converter.Convert(value); } } public object ConvertStringToNewNonNullableType(string value, Type newType) { // Do conversion form string to array - not sure how array will be stored in string if (newType.IsArray) { // For comma separated list Type singleItemType = newType.GetElementType(); var elements = new ArrayList(); foreach (var element in value.Split(',')) { var convertedSingleItem = ConvertSingleItem(element, singleItemType); elements.Add(convertedSingleItem); } return elements.ToArray(singleItemType); } return ConvertSingleItem(value, newType); } public object ConvertStringToNewType(string value, Type newType) { // If it not a nullable type, just pass through the parameters to Convert.ChangeType if (newType.IsGenericType && newType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) { if (value == null) { return null; } return ConvertStringToNewNonNullableType(value, new NullableConverter(newType).UnderlyingType); } return ConvertStringToNewNonNullableType(value, newType); } public object CallMethod(object instance, MethodInfo methodInfo, Dictionary<string, string> parameters) { var methodParameters = methodInfo.GetParameters(); var parametersForInvocation = new List<object>(); foreach (var methodParameter in methodParameters) { string value; if (parameters.TryGetValue(methodParameter.Name, out value)) { var convertedValue = ConvertStringToNewType(value, methodParameter.ParameterType); parametersForInvocation.Add(convertedValue); } else { // Get default value of the appropriate type or throw an exception var defaultValue = Activator.CreateInstance(methodParameter.ParameterType); parametersForInvocation.Add(defaultValue); } } return methodInfo.Invoke(instance, parametersForInvocation.ToArray()); } 

It supports primitive types, Nullables, and arrays of primitive types. In the case when you are going to use types that do not support the IConvertible interface, it is better to implement custom converters for each individual type.

It can be written in a more elegant way with Linq.

Vitaliy

+3
source

The value you want to convert must be an object, otherwise conversions outside the standard types will not work. You can easily convert between these types:

 object value = false; // false Type chType = typeof(String); // System.String object newValue = Convert.ChangeType(value, chType); // "false" 

It is so simple. If you want to use the method:

 public object ConvertType(object value, Type conversionType) { //Check if type is Nullable if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition() == typeof(Nullable<>)) { //If the type is Nullable and the value is null //Just return null if (value == null) { return null; } //Type is Nullable and we have a value, override conversion type to underlying //type for the Nullable to avoid exception in Convert.ChangeType var nullableConverter = new NullableConverter(conversionType); conversionType = nullableConverter.UnderlyingType; } return Convert.ChangeType(value, conversionType); } 
+4
source

Perhaps a good way to manage the "converters" is to support Dictionary<Type, IMyTypeConverter> - where IMyTypeConverter has an object Convert(string value) .

+2
source

All Articles