簡體   English   中英

使用System.Type調用泛型方法

[英]Using System.Type to call a generic method

我使用的是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);
}

我需要使用非泛型等價物包裝其中兩個調用。 具體來說,我想要

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(...)之間的部分不起作用。 GetMethod("Serialize")的調用GetMethod("Serialize")我一個AmbiguousMatchException ,因為有四個名為“ Serialize ”的方法。

然后我嘗試使用GetMethod的重載,它接受一個System.Type數組來解析綁定:

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

但這只是讓GetMethod的結果為null

如何使用反射來獲取void Serializer.Serialize<T>(Stream, T)MethodInfo ,其中Tinstance.GetType()

嘗試使用下一個代碼段來查看它是否符合您的需求。 它創建一個close類型的方法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 });
}

對於這種事情,我經常使用像這樣的幫助方法

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

暫無
暫無

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

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