5

C#/。NET 4.0と、次の機能を提供するProtocol Buffersライブラリ(protobuf-net)を使用しています。

public static class Serializer {
    public static void Serialize<T>(Stream destination, T instance);
    public static void Serialize<T>(SerializationInfo info, T instance);
    public static void Serialize<T>(XmlWriter writer, T instance);
    public static void Serialize<T>(SerializationInfo info, StreamingContext context, T instance);
    public static T Deserialize<T>(Stream source);
}

これらの呼び出しのうちの2つを、一般的でない同等のものでラップする必要があります。具体的には

void SerializeReflection(Stream destination, object instance);
object DeserializeReflection(Stream source, Type type);

Serializer実行時にのそれぞれのジェネリックメンバーを呼び出すだけです。次のコードで動作するメソッドを取得しました。DeserializeReflection

public static object DeserializeReflection(Stream stream, Type type)
{
    return typeof(Serializer)
        .GetMethod("Deserialize")
        .MakeGenericMethod(type)
        .Invoke(null, new object[] { stream });
}

そのSerializeReflection方法が私を悩ませているのです。私は最初に次のコードを試しました:

public static void SerializeReflection(Stream stream, object instance)
{
    typeof(Serializer)
        .GetMethod("Serialize")
        .MakeGenericMethod(instance.GetType())
        .Invoke(null, new object[] { stream, instance });
}

問題は、との間の部分がtypeof(Serializer)機能し.Invoke(...)ていないことです。「 。」という名前のメソッドが4つあるため、を呼び出すと、GetMethod("Serialize")が取得されます。AmbiguousMatchExceptionSerialize

次に、そのオーバーロードを使用して、バインディングを解決するためにGetMethod配列を使用してみました。System.Type

GetMethod("Serialize", new[] { typeof(Stream), instance.GetType() })

しかし、これはちょうどの結果になりGetMethod nullました。

MethodInfoリフレクションを使用してforを取得するにはどうすればよいですかvoid Serializer.Serialize<T>(Stream, T)、どこにTありinstance.GetType()ますか?

4

2 に答える 2

4

次のコードスニペットを使用して、ニーズに合っているかどうかを確認してください。メソッドのクローズ型インスタンスを作成しますpublic static void Serialize<T>(Stream destination, T instance)。この場合Stream、パラメーターとして最初のメソッドを選択しますが、この述語method.GetParameters().Any(par => par.ParameterType == typeof(Stream))を任意に変更できます

public static object DeserializeReflection(Stream stream, object instance)
{
   return typeof(Serializer)
        .GetMethods()
        .First(method => method.Name == "Serialize" && method.GetParameters().Any(par => par.ParameterType == typeof(Stream)))
        .MakeGenericMethod(instance.GetType())
        .Invoke(null, new object[] { stream, instance });
}
于 2013-01-08T19:27:04.253 に答える
2

この種のことのために、私はしばしばこのようなヘルパーメソッドを使用します

public static MethodInfo MakeGenericMethod<TSourceType>(Type genericArgument, string methodName, Type[] parameterTypes, params int[] indexesWhereParameterIsTheGenericArgument)
{
    //Get the type of the thing we're looking for the method on
    var sourceType = typeof (TSourceType);
    //Get all the methods that match the default binding flags
    var allMethods = sourceType.GetMethods();
    //Get all the methods with the same names
    var candidates = allMethods.Where(x => x.Name == methodName);

    //Find the appropriate method from the set of candidates
    foreach (var candidate in candidates)
    {
        //Look for methods with the same number of parameters and same types 
        //   of parameters (excepting for ones that have been marked as 
        //   replaceable by the generic parameter)
        var parameters = candidate.GetParameters();
        var successfulMatch = parameters.Length == parameterTypes.Length;

        if (successfulMatch)
        {
            for (var i = 0; i < parameters.Length; ++i)
            {
                successfulMatch &= parameterTypes[i] == parameters[i].ParameterType || indexesWhereParameterIsTheGenericArgument.Contains(i);
            }
        }

        //If all the parameters were validated, make the generic method and return it
        if (successfulMatch)
        {
            return candidate.MakeGenericMethod(genericArgument);
        }
    }

    //We couldn't find a suitable candidate, return null
    return null;
}

それを使用するには、あなたはします

var serializeMethod = MakeGenericMethod<Serializer>(instance.GetType(), "Serialize", new[]{typeof(stream), typeof(object)}, 1);
于 2013-01-08T19:29:44.343 に答える