简体   繁体   English

在 C# 中调用使用反射的方法时如何对参数进行自动类型转换?

[英]How to do automatic type conversion for parameters when invoking a method using reflection in C#?

I have a need to invoke methods on a type through reflection using C#.我需要使用 C# 通过反射调用类型的方法。

At run-time, my data will consist of a Dictionary containing name/value pairs.在运行时,我的数据将包含一个包含名称/值对的字典。 The names in the Dictionary will correspond to parameter names on the method I will invoke. Dictionary 中的名称将对应于我将调用的方法上的参数名称。 Also, at run-time, I will have an arbitrary assembly qualified type name and a method name.此外,在运行时,我将拥有一个任意的程序集限定类型名称和一个方法名称。 At design time, I will have no knowledge of the type and the method other than that the method will accept a variable number of parameters of type int, string, DateTime, bool, int[], string[], DateTime[] or bool[].在设计时,我不知道类型和方法,除了该方法将接受可变数量的 int、string、DateTime、bool、int[]、string[]、DateTime[] 或 bool 类型的参数[]。

I have no problem getting to the point where I can create an instance of the type using reflection and invoke the method.我可以毫无问题地使用反射创建该类型的实例并调用该方法。 I am stuck at the point where I have to convert the string values in my dictionary to the appropriate type needed by the method when I call:我被困在我必须将字典中的字符串值转换为调用时方法所需的适当类型的地步:

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

I know that I need to probably enumerate through MethodInfo.GetParameters() and perform the type conversion for each parameter.我知道我可能需要通过 MethodInfo.GetParameters() 枚举并为每个参数执行类型转换。 What I am trying to figure out is how to do this, and ideally, how to do it efficiently.我想弄清楚的是如何做到这一点,理想情况下,如何有效地做到这一点。

My research so far has involved digging into the MVC source code as it does something similar when passing form values to an ActionMethod.到目前为止,我的研究涉及深入研究 MVC 源代码,因为它在将表单值传递给 ActionMethod 时做了类似的事情。 I found ActionMethodDispatcher but it uses LINQ Expressions, with which I am unfamiliar.我找到了ActionMethodDispatcher ,但它使用了我不熟悉的 LINQ 表达式。

I also looked at similar questions on SO, but did not find anything that answers my question.我还查看了关于 SO 的类似问题,但没有找到任何可以回答我问题的内容。

I would welcome any pointers to a solution.我欢迎任何指向解决方案的指针。

Here is some code which can be used for parameters conversion:下面是一些可用于参数转换的代码:

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's 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.它支持原始类型、Nullables 和原始类型的 Arrays。 In the case when you going to use types which doesn't support IConvertible interface - it is better to implement custom converters for each individual type.如果您要使用不支持 IConvertible 接口的类型 - 最好为每个单独的类型实现自定义转换器。

It can be written in more elegant way with Linq.它可以用 Linq 以更优雅的方式编写。

Vitaliy活力

The value you want to convert should be an object, otherwise conversions outside the standard types will not work.您要转换的值应该是 object,否则标准类型之外的转换将不起作用。 You can easily convert between types like so:您可以轻松地在类型之间进行转换,如下所示:

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

It's as easy as that.就这么简单。 If you want a 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);
}

Perhaps a nice way to manage "converters" is to maintain a Dictionary<Type, IMyTypeConverter> - where IMyTypeConverter has a object Convert(string value) .也许管理“转换器”的一个好方法是维护一个Dictionary<Type, IMyTypeConverter> - 其中IMyTypeConverter有一个object Convert(string value)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM