在写 Roslyn 的时候,经常需要辅助编译的工具,而这些工具需要传入一些参数,在项目很大的时候,会发现自己传入的参数比微软限制控制台可以传入的参数大很多,这时就无法传入了参数

本文告诉大家如何使用 WriteLinesToFile 先把参数写入文件,通过文件的方式传输参数


为了让大家可以方便了解 Roslyn 编译过程,所以本文是带着一个任务来做的。通过阅读本文,大家可以学会怎么写出一些神奇的代码。

任务的背景是,在编译的过程,暗中修改一些代码,而且让开发者发现不了。

最简单的方法就是修改编译流程,修改编译流程是相对比较复杂的。但是上面在 MSBuild 可以使用很多奇怪的 Task 来做很多有趣的事情,其中就有一个强大的 Task 是 Exec ,这个命令就是使用命令行调用另一个程序。

也就是在编译的过程可以调用另一个程序,所以就把辅助编译的方法放在另一个程序去做。

但是要让这个辅助的程序跑,还需要告诉这个辅助的程序一下信息,如哪些需要编译的文件。

于是最简单的方式就是写一个 Target 来执行这个辅助的程序。先假设这个辅助的程序就放在 E:\辅助程序.exe ,调用的方法请看代码

  1. <Target Name="BitedeZawpiDafuge" BeforeTargets="CoreCompile">
  2. <Exec Command="E:\辅助程序.exe @(Compile)"></Exec>
  3. </Target>

为了让 Target 运行需要给 Target 一个 Name ,还需要告诉 VisualStudio 什么时候运行这个 Target ,于是就使用BeforeTargets="CoreCompile" 告诉 VisualStudio 在开始编译之前就执行

当然,上面的写法只是为了方便第一次接触 Roslyn 的小伙伴,如果看到了这里还是有很多内容不知道,请先看手把手教你写 Roslyn 修改编译

现在的问题是,调用 Exec 能传入的参数就是被微软限制大小,我的Compile编译文件有 10000000000000 个,于是就有很多文件无法传参数进去,这时我就无法在编译之前把代码修改掉,让项目可以成功运行,这样本渣还怎么去坑一个团队。

所以腹黑的本渣就需要一个方式传入很大的参数,找到了一个简单的方法就是使用WriteLinesToFile先把参数写到文件,然后把文件路径给辅助程序就可以

为了写入的文件可以在辅助程序找到,就需要先定义文件,请看代码

  1. <ItemGroup>
  2. <TextFile Include="Items.txt" />
  3. </ItemGroup>

把参数写入文件的方法请看代码

  1. <Target Name="WriteToFile" BeforeTargets="CoreCompile">
  2. <WriteLinesToFile File="@(TextFile)" Lines="@(Compile)" Overwrite="true" />
  3. </Target>

这时就会把 Compile 的所有文件都写入到TextFile文件

在写完之后就可以调用 Exec 执行程序了,也许这时大家会发现,本金鱼又在逗大家了,辅助的程序怎么知道 WriteLinesToFile 执行完了,会不会拿到一个空的文件。

我很负责和大家说,会的,如果现在不修改代码直接调用就会出现读取到的文件可能是空的

还记得 DependsOnTargets 这个属性?通过这个属性可以指定一个 Target 在什么时候运行,在运行辅助程序的代码就需要依赖上面的代码运行。于是修改之后的全部代码请看下面

  1. <Target Name="WriteToFile">
  2. <WriteLinesToFile File="@(TextFile)" Lines="@(Compile)" Overwrite="true" />
  3. </Target>
  4. <Target Name="BitedeZawpiDafuge" BeforeTargets="CoreCompile" DependsOnTargets="WriteToFile">
  5. <Exec Command="E:\辅助程序.exe $(MSBuildProjectDirectory)\@(TextFile)"></Exec>
  6. </Target>

现在的代码是可以运行了,从参数可以拿到文件名,然后通过读文件的方式拿到输入的文件

现在的代码已经可以运行了,但是本渣还需要继续告诉大家一些属性的设置是为什么,第一个设置的参数就是WriteLinesToFileFile ,使用这个就可以设置输出到哪个文件。第二个参数Lines就是输入的文本,不要问我文本怎么写为 line 而且是按照;分割多行的。

最后一个参数比较重要,是设置如果存在这个文件是否覆盖,如果没有选择覆盖,那么下面的辅助程序拿到的文件都会是以前的文件。我就是没有设置这个属性用了半个钟才发现读的文件都是以前的文件。

在另一个 Target 就是调用辅助程序,需要知道在参数传入的是$(MSBuildProjectDirectory)路径的,原因就是刚才写入的文件相对的就是项目所在的文件夹,所以需要从项目所在的文件夹才可以拿到这个文件。

如果是想把文件写在一个临时的文件夹,那么建议使用 $(IntermediateOutputPath)文件夹,这个$(IntermediateOutputPath)文件夹就是 obj 文件夹,建议在这个文件夹里再创建一个文件夹用来放临时的文件。

需要注意,文件同样可以写在PropertyGroup里,只是在PropertyGroup的引用是使用$请看下面代码

  1. - <ItemGroup>
  2. - <TextFile Include="Items.txt" />
  3. - </ItemGroup>
  4. + <PropertyGroup>
  5. + <TextFile>Items.txt</TextFile>
  6. + </PropertyGroup>
  7. <Target Name="WriteToFile">
  8. - <WriteLinesToFile File="@(TextFile)" Lines="@(Compile)" Overwrite="true" />
  9. + <WriteLinesToFile File="$(TextFile)" Lines="@(Compile)" Overwrite="true" />
  10. </Target>

因为 PropertyGroup 的内容是不存在 Include 特性,所以需要使用上面的方法

如果写入的文件的文件夹是不存在,就需要先创建,如写入的是 lindexi\foo.txt 就需要先判断lindexi文件夹是否存在,如果没有判断直接使用就会出现下面代码

  1. 严重性 代码 说明 项目 文件 禁止显示状态
  2. 错误 MSB3491 未能向文件“obj\Debug\netcoreapp2.0\lindexi\Items.txt”写入命令行。未能找到路径“C:\lindexi\framework\lindexi.Mvvm.framework\obj\Debug\netcoreapp2.0\lindexi\Items.txt”的一部分。 framework C:\Users\lindexi\.nuget\packages\lindexi.Mvvm.framework\0.1.52-alpha\build\lindexi.Mvvm.framework.targets 11

简单创建文件夹的方法是使用 MakeDir 请看下面代码

  1. <PropertyGroup>
  2. <TextDirectory>lindexi/</TextDirectory>
  3. <TextFile>$(TextDirectory)Items.txt</TextFile>
  4. </PropertyGroup>
  5. <Target Name="WriteToFile">
  6. <MakeDir Condition="!Exists($(TextDirectory))" Directories="$(TextDirectory)"></MakeDir>
  7. <WriteLinesToFile File="$(TextFile)" Lines="@(Compile)" Overwrite="true" />
  8. </Target>

我在测试的项目写了很长的参数,这个参数只能通过写入到文件的方式传输,不能通过参数的方法传输。测试项目请点击 Roslyn 使用 WriteLinesToFile 解决参数过长无法传入 1.0-CSDN下载

参见:

项目文件中的已知属性(知道了这些,就不会随便在 csproj 中写死常量啦) - walterlv

我搭建了自己的博客 https://lindexi.gitee.io/ 欢迎大家访问,里面有很多新的博客。只有在我看到博客写成熟之后才会放在csdn或博客园,但是一旦发布了就不再更新

如果在博客看到有任何不懂的,欢迎交流,我搭建了 dotnet 职业技术学院 欢迎大家加入


本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名林德熙(包含链接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

Roslyn 使用 WriteLinesToFile 解决参数过长无法传入的更多相关文章

  1. 2019-1-29-Roslyn-使用-WriteLinesToFile-解决参数过长无法传入

    title author date CreateTime categories Roslyn 使用 WriteLinesToFile 解决参数过长无法传入 lindexi 2019-01-29 16: ...

  2. linux下删除大量文件提示参数过长解决办法

    linux下删除大量文件提示参数过长解决办法:在当前目录下rm -rf * 在linux中删除大量文件时,直接用rm会出现:-bash: /bin/rm: 参数列表过长的错误. 这时可以用find命令 ...

  3. 解决window.location.href参数太长

    前言:一提到页面跳转,最常用的一般就是window.location.href,如果需要带参数,也许可以在后面用?拼上,但这样并不安全,而且有个更严重的问题,这样的拼接是有长度限制的,如果达到好几千个 ...

  4. 解决window.location.href参数太长 post提交数据

    前言:一提到页面跳转,最常用的一般就是window.location.href,如果需要带参数,也许可以在后面用?拼上,但这样并不安全,而且有个更严重的问题,这样的拼接是有长度限制的,如果达到好几千个 ...

  5. js代码生成form,解决mvc的url参数过长问题

    在MVC项目中,通常下载的文件的简单方式是直接采用 location.href+查询参数方式. var searchParams = { studentName: $("#StudentNa ...

  6. excel导出使用get请求参数过长问题

    遇到的问题: excel导出功能时,使用的是window.location.href=url也就是get请求.当传入参数过长的时候就报了414,地址过长的错误. 解决思路: 将get请求换为post请 ...

  7. Ajax请求参数较长导致请求失败

    Ajax请求参数比较长,第5行参数大概1100个字符吧,是接口的请求报文. $.ajax({ type:"POST", url:"${ctx}/test.action?m ...

  8. Java可变参数/可变长参数

    Java可变参数/可变长参数 传递的参数不确定长度,是变长的参数,例如小例子: package demo; public class Demo { public static int sum(int ...

  9. CSS样式 解决文字过长显示省略号问题

    一.CSS样式 解决文字过长显示省略号问题 1.一般样式 一般 css 样式,当宽度不够时,可能会出现换行的效果.这样的效果在某些时候肯定是不行的,可以修改 css 样式来解决这个问题. <!D ...

随机推荐

  1. 使用 Swift 构建自定义的ActivityIndicator View

    目前在自己的个人项目里,已经开始使用Swift去编写代码.这篇文章把项目中自己设计的一个ActivityIndicator View展示给大家. 在开始之前,我们先看看最终的效果,如下图: 我建议大家 ...

  2. python 缺失值处理

  3. firefox扩展开发(一) : 扩展的基本结构

    用过firefox的人肯定要安装firefox的扩展,这样才能发挥火狐的全部实力.一般扩展是一个后缀为.xpi的文件,其实这个文件就是zip格式的压缩包,压缩了一个扩展所需要的所有目录和文件,基本的目 ...

  4. MVC设计之MVC设计模式(介绍)

    mvc介绍; 首先先引用一个百度百科的介绍: MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用 ...

  5. hdu1421 dp

    用dp[i][j]表示放了i件物品,j对时的最小值. dp[i-2][j-1]表示取当前的 dp[i-1][j]表示不取当前的. #include<stdio.h> #include< ...

  6. 机房收费系统之【只允许一个MDI窗体 错误:426】 标签: vb 2014-08-15 10:36 1149人阅读 评论(23)

    机房收费系统的主窗体是MDI窗体,为了在这个窗体上添加控件,所以我们在窗体上添加了picture控件,在MDI窗体中,子窗体实际上位于MDIClient里,即子窗体的父窗体就是MDIClient,而放 ...

  7. ADT上跑java application

    Invalid layout of java.lang.String at value## A fatal error has been detected by the Java Runtime En ...

  8. HDU_1087-Super Jumping! Jumping! Jumping!

    Super Jumping! Jumping! Jumping! Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K ...

  9. qt 在ui界面添加控件后在cpp文件中无法调用?

    问题:qt 在ui界面添加控件后在cpp文件中无法调用? 解决方法:在build选项中选择“重新build项目”,再次在cpp中调用添加的控件发现可以调用了. 还有一种情况导致添加控件后无法调用,就是 ...

  10. 知识点补充,set集合,深浅copy

    一:对之前知识点的补充 1;字符串(str)中的join方法.把列表转换成字符串 2;列表list[ ]和字典dic{ }在循环过程中不能字节删除.需要把要删除的内容记录在新列表中.然后在循环新列表, ...