[英]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
,其中T
是instance.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.