1

我正在使用单声道的 Mono.Cecil 包,当我从自定义 msbuild 任务调用以下命令时遇到了问题:

ModuleDefinition.Write(AssemblyFileName, new WriterParameters { WriteSymbols = true });

该程序集保存得很好,并且完全符合我的需要。如果我更改了程序集文件名以测试是否创建了 pdb,它是并且当替换为另一个 pdb 时,它正在正确调试。但是,当我正常构建时,程序集的 pdb 仍然是旧的 pdb。我认为 mono 正在创建 pdb,而 msbuild 正在用旧的 pdb 覆盖它。

这是我试图导入项目的目标:

<PropertyGroup>
    <TaskAssemblyFileDir>$(SolutionDir)PropertyObserver.Tasks\$(OutDir)</TaskAssemblyFileDir>
    <TaskAssemblyFileUnescapeDir>$([MSBuild]::Unescape('$(TaskAssemblyFileDir)'))</TaskAssemblyFileUnescapeDir>
    <TaskAssemblyFile>$(TaskAssemblyFileUnescapeDir)PropertyObserver.Tasks.dll</TaskAssemblyFile>
</PropertyGroup>
<UsingTask TaskName="PropertyObserverTask" AssemblyFile="$(TaskAssemblyFile)" />
<Target Name="PropertyObserver" DependsOnTargets="AfterBuild">
    <PropertyObserverTask AssemblyPath="$(TargetPath)" />
</Target>

我不确定创建 pdb 的目标 msbuild 调用是什么。我以为它是 AfterBuild,但事实并非如此。

任何意见将是有益的。

4

1 回答 1

0

如果要应用自定义重写,覆盖 obj 文件夹中的目标文件很重要。

这是至关重要的,因为 msbuild 从这里复制这些文件。

在这里查看我的答案

在我的示例中,除了我的重写任务之外,我还使用 PostSharp。

但这对您的情况没有问题:

<PropertyGroup>
    <CompileDependsOn>
        $(CompileDependsOn);
        ApplyILRewriting
    </CompileDependsOn>
    <BuildDependsOn>
        $(BuildDependsOn);
        AfterILRewritingPostBuild
    </BuildDependsOn>
</PropertyGroup>

<Target Name="ApplyILRewriting">
    <ILTransformationTask IntermediateAssemblyPath="$(ProjectDir)$(BaseIntermediateOutputPath)$(Configuration)\$(TargetFileName)" />
</Target>
<!-- Override this target in another file. Build your nuget packages here for example. -->
<Target Name="AfterILRewritingPostBuild">
</Target>

我的解决方案最酷的部分是,转换程序集的代码是从目标程序集中加载的。因此,您可以只在属性上实现一个接口并将该属性放在您的目标类型上。它将为应用于目标的每个属性在接口上运行该方法。

这使您能够在目标程序集中拥有重写指令,这意味着您可以轻松地为每个项目添加自己的转换。

如您所见,我在 obj 文件夹中传递了程序集的路径。我的解决方案是这样工作的(我现在不想发布完整的源代码,抱歉):

  1. 在 obj 文件夹中创建 pre transform 文件夹
  2. 将所有文件从 obj/ 复制到文件夹
  3. 创建一个后期转换文件夹
  4. 将所有文件从 obj/ 复制到文件夹
  5. 使用反射检查类型:
    • 加载输出程序集的引用程序集
    • 过滤继承 ITransformation 接口的属性类型
    • 查找应用了这些属性类型的类型
  6. 使用转换后目录中的 cecil 加载匹配的程序集和类型
  7. 对您反映在类型上的属性执行 Transform(reflectionDeclaringType, cecilDeclaringTypeDefinition) 方法;这是您的自定义 cecil 代码使用 ITransformation 接口应用重写的地方

我还创建了另一个接口,不是将转换应用于单个类型,而是应用于整个程序集。

所以我最终得到了 ITypeTransformation 和 IAssemblyTranformation。一个范围为程序集,也仅通过反射和 cecil 程序集。ITypeTransformation 通过反射,cecil 组装和反射,cecil 类型

转换的示例可能是:

public class TestTypeTransformation : Attribute, ITypeTransformationAttribute
{
     public void ApplyTransformation(
            Assembly preTransformationReflectionAssembly, 
            AssemblyDefinition postTransformationCecilAssembly, 
            Type reflectionType, 
            TypeDefinition cecilType)
    {
        // Your custom rewriting here
    }
}
于 2016-06-25T08:20:03.400 回答