Code Bye

C#如何获取所有已加载类型?

这上一个帖子中,有人提到profiler api,虽然可以找到所有类型,但是监视每一个对象代价太大,我仅仅需要找到这些类型信息,不适合我的需求。

 

50分
前面说的dnlib查找TypeSpec表,在我的试验工程里,使用如下代码:
pre class=”brush: csharp”>
var md = dnlib.DotNet.ModuleDefMD.Load(typeof(Program).Assembly.Location);
for (uint i = 1; i <= md.MetaData.TablesStream.TypeSpecTable.Rows; i++)
{
    var t = md.ResolveTypeSpec(i);
    Console.WriteLine(t.FullName);
}
/pre>
可以打印出来如下结果:
pre class=”brush: text”>
System.EventHandler`1<System.Net.Sockets.SocketAsyncEventArgs>
System.Func`2<System.Int32,System.Byte>
System.Nullable`1<!!0>
!!0
System.Func`2<System.Byte,System.Int32>
System.Func`2<System.Byte,System.String>
System.Func`2<System.String,System.Collections.Generic.IEnumerable`1<System.Byte>>
System.Collections.Generic.List`1<System.Int32>
/pre>
.net的反射无法找到TypeSpec信息,所以想找它就只好使用第三方工具解析元数据了。不过就像之前说的,动态MakeGenericType出来的type这样当然找不到。
你这个需求的动机是什么?我挺感兴趣,如果说具体点说不定能找到其它方案。
引用 1 楼 github_22161131 的回复:

前面说的dnlib查找TypeSpec表,在我的试验工程里,使用如下代码:

想做一个静态对象内存分析的API库,可以根据实际情况做适当分析,不做分析的时候对程序没有任何影响,分析也可以与程序正常并行工作。

引用 1 楼 github_22161131 的回复:

前面说的dnlib查找TypeSpec表,在我的试验工程里,使用如下代码:..

看起来dnlib能解决一部分问题,泛型这一块,不是读取文件中的元数据可以解决的。
另外即使非泛型,也不能粗暴的遍历所有类型,因为有很多类型根本就不需要初始化。


100分
嗯,静态元数据分析只能知道编译时有哪些类型,运行时哪些类型被使用根据执行的分支每次运行都可能不一样。要做运行时内存分析的话,我看能找到的方案都是使用profiling api,如果这个不可接受,我觉得只能使用改写程序集的方式,静态的话就是使用il weaving工具或者cecil/dnlib这种底层工具修改程序集,动态的话就是运行时动态改写方法。
看了你的fastCSharp代码,你是觉得要在需要的那么多(目前30个)静态构造处加那个checkMemory.Add麻烦?这个我觉得就用il weaving方式好了,基于Fody(它基于cecil),自己写个addin,编译的时候自动处理下生成的程序集。

5分
你可以写
public IEnumerable<Type> GetTypes()
{
    foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
        foreach (var t in GetTypes(asm))
            yield return t;
}
private IEnumerable<Type> GetTypes(System.Reflection.Assembly asm)
{
    Type[] ts;
    try
    {
        ts = asm.GetTypes();
    }
    catch { yield break; }
    foreach (var t in ts)
        yield return t;
}
如果你要遍历的类型可能不是被当前应用程序直接引用的(而是间接引用的),那么你可以在
   GetTypes(System.Reflection.Assembly asm)
方法中的递归地查询其 asm.GetReferencedAssemblies() 的 Assembly。当然要使用一个集合,将已经处理过的 Assembly 保存起来,防止重复处理。
如果你需要查找当前应用程序工作目录下的所有 .exe、.dll文件,那么也可以使用 Assembly.Load 动态加载它们,然后在调用
  GetTypes(System.Reflection.Assembly asm)
也可以让用户把需要扫描的 Assembly 在 config 文件中注册一下。
由于这种东西特别简单,对于一个非常大、非常复杂的系统,这种遍历只需要花掉不到一秒钟的时间代价。
关键是,不要反复进行遍历,而要仅仅遍历一次!
引用 7 楼 sp1234 的回复:

由于这种东西特别简单,对于一个非常大、非常复杂的系统,这种遍历只需要花掉不到一秒钟的时间代价。
关键是,不要反复进行遍历,而要仅仅遍历一次!

大神给的方案果然是神级的啊,只可惜咱凡人没有那神力。
fieldset>

引用 4 楼 github_22161131 的回复:

嗯,静态元数据分析只能知道编译时有哪些类型,运行时哪些类型被使用根据执行的分支每次运行都可能不一样。要做运行时内存分析的话,我看能找到的方案都是使用profiling api,如果这个不可接受,我觉得只能使用改写程序集的方式,静态的话就是使用il weaving工具或者cecil/dnlib这种底层工具修改程序集,动态的话就是运行时动态改写方法。
看了你的fastCSharp代码,你是觉得要在需要的那么多(目前30个)静态构造处加那个checkMemory.Add麻烦?这个我觉得就用il weaving方式好了,基于Fody(它基于cecil),自己写个addin,编译的时候自动处理下生成的程序集。

谢谢你的关注,现在这种手动方式,只能处理可控的程序集,而且确实要花一点点时间,虽然时间不多。
另外不需要使用第三方工具,使用代码生成的话也可以解决这个手动的问题,不过感觉性价比不高。
就是希望有.NET类库中的API直接获取到。


100分
除了profiler api,楼上各位的方案都只能判断csc编译时加载的assembly中包含的对象,不能判断代码运行后动态加载的对象。
我对楼主意思的理解是,楼主想做一个分析器,能分析到任何运行中的.net程序创建了那些类型的对象,以及这些类型的详细签名。
.net程序运行时,Runtime创建的所有对象都在GC中,所以你要监视GC就能获得所有动态创建的对象类型。
可惜,.net本身没有提供访问GC对象的API.
鉴于WinDBG一类工具都能非常完美的监视GC状态,所以应该是存在这样的API接口,不过多半是native的。
有本书叫Customizing the Microsoft? .NET Framework Common Language Runtime,这里边或许会有答案,N年前似懂非懂的翻了一遍,现在已经记不得了。
/div>

35分
刚刚翻了一下,这本书的13章的确讲了如何自定义CLR中的Memory Managers和配置GC,你可以去研究下。
http://download.csdn.net/detail/yph123456/3092808

5分
.Net好像有个GetTypes这类的函数

CodeBye 版权所有丨如未注明 , 均为原创丨本网站采用BY-NC-SA协议进行授权 , 转载请注明C#如何获取所有已加载类型?