[英]How to get typeof(List<>) from typeof(List<T>) by removing generic argument
[英]Generics Fun: Where typeof(List<T>) != typeof(List<T>), and using Reflection to get a generic method, with generic parameters
這只是.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? 潛在地,編譯器期望具有泛型參數T
的泛型類型List<>
- 唯一的問題是,您不能逐字地使用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;
}
}
那是因為你的類型是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;
}
按預期返回您的方法。
您無法創建表示具有未知T
List<T>
的Type
實例。 這就是GetGenericTypeDefinition
和List<>
的用途。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.