8

C# を使用して、リフレクションを通じて型のメソッドを呼び出す必要があります。

実行時に、データは名前と値のペアを含む Dictionary で構成されます。Dictionary 内の名前は、呼び出すメソッドのパラメーター名に対応します。また、実行時に、任意のアセンブリ修飾型名とメソッド名を持ちます。設計時には、メソッドが int、string、DateTime、bool、int[]、string[]、DateTime[]、または bool 型の可変数のパラメーターを受け入れること以外に、型とメソッドについての知識はありません。 []。

リフレクションを使用して型のインスタンスを作成し、メソッドを呼び出すことができるようになるまで問題はありません。呼び出すときに、辞書内の文字列値をメソッドで必要な適切な型に変換する必要がある時点で立ち往生しています。

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

おそらく MethodInfo.GetParameters() を介して列挙し、各パラメーターの型変換を実行する必要があることはわかっています。私が理解しようとしているのは、これを行う方法、そして理想的には効率的に行う方法です。

私のこれまでの調査では、フォームの値を ActionMethod に渡すときに MVC ソース コードが同様のことを行うため、MVC ソース コードを掘り下げました。ActionMethodDispatcherを見つけましたが、慣れていない LINQ 式を使用しています。

SOに関する同様の質問も見ましたが、私の質問に答えるものは見つかりませんでした。

解決策への指針を歓迎します。

4

3 に答える 3

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);
}
于 2011-07-11T08:38:22.443 に答える
4

パラメータの変換に使用できるコードを次に示します。

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

プリミティブ型、Nullable、およびプリミティブ型の配列をサポートしています。IConvertible インターフェイスをサポートしない型を使用する場合は、個々の型ごとにカスタム コンバーターを実装することをお勧めします。

Linq を使用すると、よりエレガントな方法で記述できます。

活力

于 2011-07-11T08:29:56.330 に答える
2

おそらく、「コンバーター」を管理するための優れた方法は、Dictionary<Type, IMyTypeConverter>-を維持するIMyTypeConverterことobject Convert(string value)です。

于 2011-07-10T14:18:09.657 に答える