列出运行时从开放泛型类型创建的封闭类型 [英] List closed types that runtime has created from open generic types
问题描述
当我列出当前AppDomain中的所有类型时,我会看到具有泛型占位符的泛型类型。然而,如果我用一个类型实例化我的泛型类型,然后列出appDomain中的所有类型,我没有看到新创建的闭合类型。
在示例中下面,输出只是:
pre $ f $ f $ f
code $
我正在寻找关闭的类型:
Foo `1 [System.Int32]
有没有办法查看运行时创建的封闭类型对我来说,基于我的开放泛型类型?
class Foo< T>
{
}
类程序
{
static void Main(string [] args)
{
var tmp =新的Foo< int>();
ListTypes();
从类中的程序集中获取AppDomain.CurrentDomain.GetAssemblies()中的程序集中的类型var b =
$ b $ GetTypes()
其中type.Name.Contains(Foo)
选择类型;
foreach(var类型)
Console.WriteLine(type.ToString());
}
}
我也尝试通过泛型参数找到所有类型希望发现封闭类型。
class Foo< T>
{
}
class Bar
{
}
class程序
{
static void Main(string [] args)
{
var tmp = new Foo< Bar>();
ListTypes();
从类中的程序集中获取AppDomain.CurrentDomain.GetAssemblies()中的程序集中的类型var b =
$ b $ GetTypes()
其中type.IsGenericType
&&类型.GetGenericArguments()。包含(typeof(Bar))
选择类型;
foreach(var类型)
Console.WriteLine(type.ToString());
}
}
这只是为了满足我的好奇心。
解决方案据我所知,在这种情况下
Foo< T> code>是一个开放的未绑定泛型类型,因此在运行时,CLR将使用它作为蓝图/框架来构造和关闭泛型类型,并指定类型参数类型(
Foo
骨架的运行时构建实现。/ code>, Foo< object>
等)。所以基本上Foo< int>
是Foo< T>
现在,在运行时,可以通过使用
typeof()来获取
或Foo
类型Foo< int>)typeof(Foo>)MakeGenericType(new [] {typeof(int)})
同样的键入
并且它没有任何意义。但仔细观察,你会看到typeof(Foo
和) typeof(Foo< int>)
共享相同的元数据令牌和GUID。
另一个有趣的地方是
typeof(Foo< int>)。Assembly 将会是你期望的,但正如你已经注意到,你不能从大会得到这种类型。因为
Foo
未在程序集中定义(您可以使用Reflector / ILSpy)。在运行时,CLR将为Foo
(如此 - 构造一个无界的开放泛型类型定义的封闭类型)并给它一个创建(构建) Foo
的专用(关闭 ;Type
。所以除非CLR直接以某种方式公开它在运行时产生的封闭泛型类型列表,否则你是不幸的。
另外这里有一个片段可以证实我我说:
即使每个通用类型的构造,例如Node<表格>
和节点< String>具有自己独特的类型标识,CLR可以
重用类型
实例之间的大部分实际的JIT编译代码。这极大地减少了代码膨胀,并且可能是
,因为泛型类型的各种实例在
运行时扩展。所有在编译时存在的构造类型都是
类型的引用。当程序集A和程序集B都引用在第三个程序集中定义的泛型类型
时,它们的构造类型在
运行时展开。这意味着,除了共享CLR类型标识
(如果适用)之外,还可以从程序集A和B中输入实例,也可以共享运行时资源,例如本地代码和扩展元数据。
http://msdn.microsoft.com/en-us /magazine/cc163683.aspx
When I list all the types in the current AppDomain, I see my generic types with the generic placeholders. However, if I instantiate my generic types with a type and then list all the types in the appDomain, I don't see the newly created closed types.
In the example below, the output is only:
Foo`1[T]
I'm looking for the closed type:
Foo`1[System.Int32]
Is there a way to see the closed types that the runtime has created for me based on my open generic types?
class Foo<T> { } class Program { static void Main(string[] args) { var tmp = new Foo<int>(); ListTypes(); } private static void ListTypes() { var types = from assembly in AppDomain.CurrentDomain.GetAssemblies() from type in assembly.GetTypes() where type.Name.Contains("Foo") select type; foreach (var type in types) Console.WriteLine(type.ToString()); } }
I have also tried finding all types by the generic argument in hopes of discovering the closed type.
class Foo<T> { } class Bar { } class Program { static void Main(string[] args) { var tmp = new Foo<Bar>(); ListTypes(); } private static void ListTypes() { var types = from assembly in AppDomain.CurrentDomain.GetAssemblies() from type in assembly.GetTypes() where type.IsGenericType && type.GetGenericArguments().Contains(typeof(Bar)) select type; foreach (var type in types) Console.WriteLine(type.ToString()); } }
This is just to satisfy my curiosity.
解决方案As far as I can understand in this case
Foo<T>
is an open unbound generic type, so at runtime the CLR will use it as a blueprint/skeleton to construct and close a generic type with the type parameter type specified (Foo<int>
,Foo<object>
, etc.). So basicallyFoo<int>
is a runtime constructed implementation of theFoo<T>
skeleton.Now, at run-time you can get the type of
Foo<int>
either by usingtypeof(Foo<int>)
ortypeof(Foo<>).MakeGenericType(new[] { typeof(int) })
and it's not the sameType
and it wouldn't make sense for it to be. But look closer and you will see that bothtypeof(Foo<T>)
andtypeof(Foo<int>)
share the same metadata token and GUID.Another interesting thing is that
typeof(Foo<int>).Assembly
will be what you would expect, but as you've noticed already you can't get that type from the Assembly.That's because
Foo<int>
is not defined in the assembly (you can check the assembly metadata with Reflector/ILSpy). At run-time the CLR will create ("construct") a specialized ("closed") version of theFoo<T>
forFoo<int>
(so - constructed closed type of an unbounded open generic type definition) and "give" it aType
. So unless the CLR exposes directly somehow the list of closed generic types it generates at run-time you are out of luck.Also here is a snippet that might confirm what I am saying:
Even though each construction of a generic type, such as Node< Form > and Node< String >, has its own distinct type identity, the CLR is able to reuse much of the actual JIT-compiled code between the type instantiations. This drastically reduces code bloat and is possible because the various instantiations of a generic type are expanded at run time. All that exists of a constructed type at compile time is a type reference. When assemblies A and B both reference a generic type defined in a third assembly, their constructed types are expanded at run time. This means that, in addition to sharing CLR type-identities (when appropriate), type instantiations from assemblies A and B also share run-time resources such as native code and expanded metadata.
这篇关于列出运行时从开放泛型类型创建的封闭类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!