如何查找 C# 类文件的所有依赖项(类文件)

发布于 2024-12-11 05:04:41 字数 284 浏览 0 评论 0原文

我有许多 C# 测试类(NUnit 测试脚本,在 Mono 上编译)。

我不想像往常一样将所有单元测试编译成一个大程序集,而是将各个类文件编译成单独的程序集。为此,我想进行依赖性分析,以便我可以自动生成单独的程序集。

我正在寻找的类似于 Java 存在的类依赖分析器

I have a number of test classes in C# (NUnit Test scripts, compiling on Mono).

Instead of compiling all unit tests into one big assembly, as usual, I'd like to compile the individual class files into separate assemblies. To do so, I'd like to do a dependency analysis, so I can generate the separate assemblies automatically.

What I'm looking for is similar to class dependency analyser which exists for Java

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

猥琐帝 2024-12-18 05:04:41

看看莫诺·塞西尔。

该库能够“反映”(这不是一个很好的名字)实际的装配图像以进行分析。这假设您愿意编译为“大”程序集,以便使用 Mono.Cecil 运行依赖性分析。

编辑 事实上,您可以简单地使用 Cecil 来复制“大”程序集,同时过滤掉其中的某些部分。这样,您就不会因为编译单独的程序集而变得太复杂;请参阅 CecilRoundtrip 示例,了解如何操作的示例在 Cecil 中往返(读取 -> 操作 -> 保存)程序集。

我之前发布过相当广泛的示例,说明如何使用 Mono Cecil 进行“高级”搜索(本质上是静态调用树搜索):

对您最有用的绝对最低限度可能是:

var types = assemblies
    .SelectMany(assembly => assembly.MainModule.Types.Cast<TypeDefinition>());

var dependencies = types.ToDictionary(
    key => key,
    typedef => new HashSet<string>(typedef.Methods.Cast<MethodDefinition>()
                .Where(method => null != method.Body) // ignore abstracts and generics
                .SelectMany(method => method.Body.Instructions.Cast<Instruction>())
                .Select(instr => instr.Operand)
                .OfType<TypeReference>().Distinct()
          //    .Where(type => !type.Namespace.StartsWith("System"))
                .Select(type => type.Name)));

foreach (var entry in dependencies)
{
     Console.WriteLine("{0}\t{1}", entry.Key.Name, string.Join(", ", entry.Value.ToArray()));
}

注意注释行可以选择过滤掉框架中的内容(System.StringSystem.Char 等)。

这将列出每个声明类型所需的类型。要列出使用的类型,只需在对程序集名称的查找上添加标记:

                .Select(type => type.Module.Assembly.Name.Name)));

第一种示例输出(需要类型):

SegmentSoortKenmerk     SegmentSoortKenmerk
OperatorValue
Koppelpad       Koppelpad, CodeLeidendVolgend
RedenWaarschuwing
RelExceptions
GecontroleerdDocument   GecontroleerdDocument, GecontroleerdDocument[]
OwiExtraKenmerk OwiExtraKenmerk, Gegeven, BackofficeRelatie
Entiteit        Entiteit, SleutelSysteemObject[], EniteitType

类似的查询,但使用程序集名称查找:

SegmentSoortKenmerk     Lspo.Business
OperatorValue
Koppelpad       Lspo.Business
RedenWaarschuwing
RelExceptions
GecontroleerdDocument   Lspo.Business
OwiExtraKenmerk Lspo.Business
Entiteit        Lspo.Business

Have a look at Mono Cecil.

This library has the capability to 'reflect' (not a very good name for it) on the actual assembly image to do analysis. This assumes that you would be willing to compile down to a 'big' assembly in order to run the dependency analysis using Mono.Cecil.

Edit In fact, you might simply use Cecil to copy the 'big' assembly while filtering out parts of it. That way, you'll not have much of the complexity of compiling the separate assemblies; Look at CecilRoundtrip sample for an example of how to roundtrip (read -> manipulate -> save) assemblies in Cecil.

I have previously published quite extensive examples of how to use Mono Cecil for 'advanced' searches (static call tree search, in essence):

The absolute bare minimum that would be most useful to you would probably be:

var types = assemblies
    .SelectMany(assembly => assembly.MainModule.Types.Cast<TypeDefinition>());

var dependencies = types.ToDictionary(
    key => key,
    typedef => new HashSet<string>(typedef.Methods.Cast<MethodDefinition>()
                .Where(method => null != method.Body) // ignore abstracts and generics
                .SelectMany(method => method.Body.Instructions.Cast<Instruction>())
                .Select(instr => instr.Operand)
                .OfType<TypeReference>().Distinct()
          //    .Where(type => !type.Namespace.StartsWith("System"))
                .Select(type => type.Name)));

foreach (var entry in dependencies)
{
     Console.WriteLine("{0}\t{1}", entry.Key.Name, string.Join(", ", entry.Value.ToArray()));
}

Note the commented line optionally filters out things from the framework (System.String, System.Char etc.).

This will list required types per declared type. To list types used, simply tag on the lookup to assembly name:

                .Select(type => type.Module.Assembly.Name.Name)));

Sample output of the first kind (types required):

SegmentSoortKenmerk     SegmentSoortKenmerk
OperatorValue
Koppelpad       Koppelpad, CodeLeidendVolgend
RedenWaarschuwing
RelExceptions
GecontroleerdDocument   GecontroleerdDocument, GecontroleerdDocument[]
OwiExtraKenmerk OwiExtraKenmerk, Gegeven, BackofficeRelatie
Entiteit        Entiteit, SleutelSysteemObject[], EniteitType

Similar query but using the assembly name lookup:

SegmentSoortKenmerk     Lspo.Business
OperatorValue
Koppelpad       Lspo.Business
RedenWaarschuwing
RelExceptions
GecontroleerdDocument   Lspo.Business
OwiExtraKenmerk Lspo.Business
Entiteit        Lspo.Business
月亮是我掰弯的 2024-12-18 05:04:41

假设您想在 mono 上运行 nunit 测试,那应该可以正常工作(我很高兴在 mono 2.10.6 上使用 NUnit 2.5 和 2.4 )。

一种常见的错误是仅复制或跟踪包含测试的 .dll 文件。与任何程序一样,测试也具有依赖项,在您的情况下,它们至少是 nunit.framework.dll 加上您希望测试的类/程序集(及其任何依赖项),

如果您想要的话然而,要找到给定 dll 引用的程序集(它需要运行的东西),您可以很容易地做到这一点:

using System.Reflection;

void PrintRefs( string dllfile ){
  var asm = Assembly.ReflectionOnlyLoad ( dllfile );

  foreach ( var aname in asm.GetReferencedAssemblies() ){
    Console.WriteLine( aname.Name );
  }
}

请注意,这只会找到程序或库编译时使用的程序集的名称,而不是它可能动态加载的任何程序集的名称。运行时。

Assuming you want to run nunit tests on mono, that should work just fine, ( I am happily using NUnit 2.5 and 2.4 on mono 2.10.6 ).

One common mistake is only copying or keeping track of the .dll file containing the tests. Like any program, the test has dependencies, in your case, they will at least be nunit.framework.dll plus the class/assembly you wish to test ( and any of it's dependencies )

If all you want however is to find the assemblies a given dll references (things it needs to run) you can do this quite easily:

using System.Reflection;

void PrintRefs( string dllfile ){
  var asm = Assembly.ReflectionOnlyLoad ( dllfile );

  foreach ( var aname in asm.GetReferencedAssemblies() ){
    Console.WriteLine( aname.Name );
  }
}

Beware, this will only find the names of assemblies the program or library was compiled with, not any that it might dynamically load at runtime.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文