簡體   English   中英

在 C# 中調用使用反射的方法時如何對參數進行自動類型轉換?

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

我需要使用 C# 通過反射調用類型的方法。

在運行時,我的數據將包含一個包含名稱/值對的字典。 Dictionary 中的名稱將對應於我將調用的方法上的參數名稱。 此外,在運行時,我將擁有一個任意的程序集限定類型名稱和一個方法名稱。 在設計時,我不知道類型和方法,除了該方法將接受可變數量的 int、string、DateTime、bool、int[]、string[]、DateTime[] 或 bool 類型的參數[]。

我可以毫無問題地使用反射創建該類型的實例並調用該方法。 我被困在我必須將字典中的字符串值轉換為調用時方法所需的適當類型的地步:

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

我知道我可能需要通過 MethodInfo.GetParameters() 枚舉並為每個參數執行類型轉換。 我想弄清楚的是如何做到這一點,理想情況下,如何有效地做到這一點。

到目前為止,我的研究涉及深入研究 MVC 源代碼,因為它在將表單值傳遞給 ActionMethod 時做了類似的事情。 我找到了ActionMethodDispatcher ,但它使用了我不熟悉的 LINQ 表達式。

我還查看了關於 SO 的類似問題,但沒有找到任何可以回答我問題的內容。

我歡迎任何指向解決方案的指針。

下面是一些可用於參數轉換的代碼:

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 和原始類型的 Arrays。 如果您要使用不支持 IConvertible 接口的類型 - 最好為每個單獨的類型實現自定義轉換器。

它可以用 Linq 以更優雅的方式編寫。

活力

您要轉換的值應該是 object,否則標准類型之外的轉換將不起作用。 您可以輕松地在類型之間進行轉換,如下所示:

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

也許管理“轉換器”的一個好方法是維護一個Dictionary<Type, IMyTypeConverter> - 其中IMyTypeConverter有一個object Convert(string value)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM