这只是.NET的另一天。直到我必须使用泛型参数获取静态类的泛型方法,使用反射进行序列化。听起来不是那么糟糕。 GetRuntimeMethod("x", new[] { type })
,像往常一样应该做到这一点,或者我想。
现在,此方法为以下变量保持返回null:
public static Surrogate<T> BuildSurrogate<T>(List<T> collection)
。
因此,快速复制到LinqPad,然后运行GetRuntimeMethods
,它似乎拥有所有预期的方法。当然,我想也许,GetRuntimeMethod的行为有些不对劲,所以,我掀起了一个快速扩展,GetRuntimeMethodEx
迭代,令我惊讶的是,它失败了。什么?怎么可能失败。 GetRuntimeMethods具有我需要的methodInfo。
所以,我最终将扩展分解成部分以了解究竟发生了什么,如下面的代码所示。事实证明(cType != cGivenType)
总是最终为真。
但快速检查显示它们是相同的“明显”类型 - List<T>
。现在完全混淆了两个typeof(List<T>)
转储的差异,事实证明它们不一样!
两者中的MetadataToken
完全相同。然而,RuntimeTypeHandle
是不同的。给定类型具有属于AssemblyQualifiedName
的正确FullName
和System.Collections.Generic.List``1, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
。大。但奇怪的是,泛型方法的类型,它们都是“null
”!所以,基本上,List<T>
是一个神奇的类型,没有相应的程序集(!?)。 It exists, but doesn't
。多么迷人!
这是两者之间差异的快速转储,这是相关的。
注意GenericTypeParameters
和IsGenericTypeDefinition
- 它们似乎很有意义。除了奇怪之外,现在如何在MethodInfo上创建一个匹配此类型的Type?潜在地,编译器期望通用类型List<>
具有泛型参数T
- 唯一的问题是,您不能用T
逐字地创建泛型类型。 T
必须是某种东西,现在使相等无效。
private void Main()
{
var type = typeof (List<>);
var m = typeof (Builders).GetRuntimeMethods();
var surrogateBuilder = typeof (Builders)
.GetRuntimeMethodEx("BuildSurrogate", new[] {type});
}
static class Builders
{
public static Surrogate<T> BuildSurrogate<T>(List<T> collection)
{
return new Surrogate<T>
{
Items = collection.ToArray(),
};
}
public class Surrogate<T>
{
public IEnumerable<T> Items;
}
}
public static class ReflectionExtensions
{
public static MethodInfo GetRuntimeMethodEx(
this Type type, string name, params Type[] types)
{
var m = type.GetRuntimeMethods();
var res = (m.Where(t =>
{
var n = name;
return t.Name.Equals(n);
}).FirstOrDefault(t =>
{
var px = t.GetParameters().ToArray();
var currentTypes = px.Select(p => p.ParameterType).ToArray();
if (currentTypes.Length < 1) return false;
for (var i = 0; i < types.Length; i++)
{
var cGivenType = types[i];
for (var j = 0; j < currentTypes.Length; j++)
{
var cType = currentTypes[j];
if (cType != cGivenType) return false;
}
}
return true;
}));
return res;
}
}
答案 0 :(得分:3)
这是因为您的类型是GenericTypeDefinition
(List<>
),而且反映您的课程的类型是实际的List<T>
。
您的代码无法读取,因此我从头开始编写自己的代码。重要的部分是TypesMatch
方法。
public static MethodInfo GetRuntimeMethodEx(
this Type type, string name, params Type[] types)
{
var withMatchingParamTypes =
from m in type.GetRuntimeMethods()
where m.Name == name
let parameterTypes = m.GetParameters().Select(p => p.ParameterType).ToArray()
where parameterTypes.Length == types.Length
let pairs = parameterTypes.Zip(types, (actual, expected) => new {actual, expected})
where pairs.All(x => TypesMatch(x.actual, x.expected))
select m;
return withMatchingParamTypes.FirstOrDefault();
}
private static bool TypesMatch(Type actual, Type expected)
{
if (actual == expected)
return true;
if (actual.IsGenericType && expected.IsGenericTypeDefinition)
return actual.GetGenericTypeDefinition() == expected;
return false;
}
按预期返回您的方法。
您无法创建代表Type
且未知List<T>
的{{1}}个实例。这是T
和GetGenericTypeDefinition
的用途。