2011-07-10 24 views
7

我需要通过使用C#反射来调用类型的方法。如何在C#中使用反射调用方法时对参数进行自动类型转换?

在运行时,我的数据将由包含名称/值对的字典组成。 Dictionary中的名称将与我将调用的方法的参数名称相对应。另外,在运行时,我将拥有一个任意程序集限定类型名称和一个方法名称。在设计时,除了该方法将接受可变数量的类型为int,string,DateTime,bool,int [],string [],DateTime []或bool的参数外,我不知道类型和方法[]。

我没有问题,我可以创建一个使用反射类型的实例并调用该方法。我被困在那里我有字符串值,在我的字典转换为通过时,我调用该方法所需的适当类型的点:

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

我知道,我需要有可能通过MethodInfo.GetParameters枚举()并为每个参数执行类型转换。我想弄清楚的是如何做到这一点,理想的是如何有效地做到这一点。

到目前为止,我的研究涉及挖掘MVC源代码,因为它在将表单值传递给ActionMethod时做了类似的事情。我发现ActionMethodDispatcher,但它使用LINQ表达式,我不熟悉。

我也看过类似的问题,所以没有找到任何答案我的问题。

我会欢迎任何指向解决方案的指针。

+0

可能有更好的方法来解决它,但我用[System.Convert](http://msdn.microsoft.com/en-us/library/system。 convert.aspx)类似的需求。处理nullabe类型也增加了一些额外的复杂性。 – Clayton

+0

更多任意转换的另一种选择是[TypeConverter](http://msdn.microsoft.com/en-us/library/system.componentmodel.typeconverter(v = VS.100).aspx),虽然我不是确定这将如何与数组一起工作。 –

+0

@Clayton是的,我认为System.Convert将是我的后备,如果没有更优雅的东西。看起来似乎可能比循环遍历每个参数类型和在交换机中使用System.Convert(...)执行单个类型转换更有效。 –

回答

3

下面是一些代码,其可被用于参数转换:

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()); 
} 

它支持原始类型,Nullables和原始类型的阵列。 如果您要使用不支持IConvertible接口的类型,最好为每种类型实现自定义转换器。

它可以用更优雅的方式用Linq书写。

维塔利

2

也许一个管理“转换器”的好方法是维护一个Dictionary<Type, IMyTypeConverter> - 其中IMyTypeConverterobject Convert(string value)

4

要转换应该是一个对象的值,标准型外,否则转换将无法正常工作。你可以很容易地转换类型如下:

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

就这么简单。如果你想要一个方法:

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); 
} 
+0

正如我在我的评论中提到的可空类型需要一些特殊情况处理。我已经修改了你的方法,以反映你怎么可以去关于@Clayton – Clayton

+0

,谢谢。 –

相关问题