zoukankan      html  css  js  c++  java
  • 2019-11-29-Roslyn-通过-NuGet-库修改应用程序入口函数

    title author date CreateTime categories
    Roslyn 通过 NuGet 库修改应用程序入口函数
    lindexi
    2019-11-29 08:37:49 +0800
    2019-04-21 16:46:29 +0800
    Roslyn MSBuild 编译器

    我和小伙伴说只要你安装我的 NuGet 库无论你怎么做,都会调用我的 Main 函数,默认的主函数不会调用

    在程序编译的时候可以通过指定 StartupObject 指定某个命名空间里面的某个类的主函数作为入口

    在做 NuGet 包可以通过 Build 文件夹里面添加一些有趣的代码,简单的调试请创建一个简单的 Nuget 包,创建方法请看 VisualStudio 使用新项目格式快速打出 Nuget 包

    在做一个 Nuget 包的时候可以直接纯手工写一个 nuget 包,或者修改现有的 Nuget 包文件

    如我使用新项目格式打出一个 lindexi 的包,我通过安装本地nuget包

    安装完成可以在用户名的 .nuget 文件夹找到

    c:Userslindexi.nugetpackageslindexi1.0.0

    在这个文件夹里面创建 Build 文件夹,在 Build 文件夹创建 nuget 库的 id .targets 文件,如我这里的是 lindexi 就创建 lindexi.targets 文件,此时看到的文件夹如下

    │  .nupkg.metadatalindexi.1.0.0.nupkglindexi.1.0.0.nupkg.sha512lindexi.nuspec
    │
    ├─buildlindexi.targets
    │
    ├─package
    │  └─services
    │      └─metadata
    │          └─core-properties
    └─_rels

    在 lindexi.targets 文件里面可以尝试添加代码,在测试的项目每次都需要运行 git clean -xdf 清理之后才可以使用 dotnet run 运行,这样就可以减少打包

    在 targets 文件里面写的内容,只需要下一次在测试项目使用 dotnet run 就会使用

    先通过WriteLinesToFile写一个新的文件,这个文件里面包括主函数

    然后在 StartupObject 指定入口函数为刚才创建的文件

    在 targets 文件定义临时文件的存放的路径

      <PropertyGroup>
        <_GeneratedEntryPointFile>$(IntermediateOutputPath)$(MSBuildProjectName).Program.g$(DefaultLanguageSourceExtension)</_GeneratedEntryPointFile>
      </PropertyGroup>

    这里的 $(IntermediateOutputPath) 是常量,更多请看项目文件中的已知属性(知道了这些,就不会随便在 csproj 中写死常量啦) - walterlv

    上面代码是定义路径是 obj 文件夹的 xx.Program.g.cs 的文件

    然后写入新的代码

         <PropertyGroup>
             <_GeneratedProgramFileContent >
    
    <![CDATA[
            // <auto-generated>This file was created automatically</auto-generated>
            using System;
            using System.Runtime.CompilerServices;
    
            namespace Lindexi
            {
                [CompilerGenerated]
                class Program
                {
                    static void Main(string[] args)
                    {
                        Console.WriteLine("林德熙是逗比");
                    }
                }
            }
           
    ]]>
    
           </_GeneratedProgramFileContent>
    
        </PropertyGroup>

    将代码写入到文件可以使用WriteLinesToFile写入到上面定义的文件

    注意文件里面有逗号,在Roslyn how to use WriteLinesToFile to write the semicolons to file告诉大家如何解决逗号的坑

        <WriteLinesToFile File="$(_GeneratedEntryPointFile)"
                          Overwrite="true"
                          Lines="$([MSBuild]::Escape($(_GeneratedProgramFileContent)))"
                          Encoding="Unicode"/>

    文件写入之后还需要添加文件到编译

        <ItemGroup>
          <Compile Include="$(_GeneratedEntryPointFile)" />
        </ItemGroup>

    因为文件需要编译,所以这个时机需要 CoreCompile 之前,需要设置启动项目为这个文件,全部代码有点长

    <Project>
    
      <PropertyGroup>
        <_GeneratedEntryPointFile>$(IntermediateOutputPath)$(MSBuildProjectName).Program.g$(DefaultLanguageSourceExtension)</_GeneratedEntryPointFile>
      </PropertyGroup>
    
      <Target Name="_GenerateRealEntryPointType"
              BeforeTargets="CoreCompile"
              DependsOnTargets="PrepareForBuild;CoreGenerateDragonFruitProgramFile"
              Condition="'$(DisableAutoGeneratedMain)' != 'true'">
        <PropertyGroup>
          <StartupObject>Lindexi.Program</StartupObject>
        </PropertyGroup>
      </Target>
    
      <Target Name="CoreGenerateDragonFruitProgramFile"
              Condition="'$(Language)' == 'C#'"
              Outputs="$(_GeneratedEntryPointFile)">
    
          <PropertyGroup>
             <_GeneratedProgramFileContent >
    
    <![CDATA[
            // <auto-generated>This file was created automatically</auto-generated>
            using System;
            using System.Runtime.CompilerServices;
    
            namespace Lindexi
            {
                [CompilerGenerated]
                class Program
                {
                    static void Main(string[] args)
                    {
                        Console.WriteLine("林德熙是逗比");
                    }
                }
            }
           
    ]]>
    
           </_GeneratedProgramFileContent>
    
        </PropertyGroup>
    
        <WriteLinesToFile File="$(_GeneratedEntryPointFile)"
                          Overwrite="true"
                          Lines="$([MSBuild]::Escape($(_GeneratedProgramFileContent)))"
                          Encoding="Unicode"/>
    
        <ItemGroup>
          <Compile Include="$(_GeneratedEntryPointFile)" />
        </ItemGroup>
      </Target>
    </Project>

    通过这个方法就可以修改应用程序的入口,将入口程序修改为特殊的,那么这样有什么用?在System.CommandLine就使用这个方法让用户可以写出多个参数的主函数

    关于System.CommandLine请看dotnet 使用 System.CommandLine 写命令行程序

    更多编译相关请看手把手教你写 Roslyn 修改编译

  • 相关阅读:
    springboot配置redis缓存
    【spark】local模式运行
    mybatis从入门到精通(二) 增删查改
    学习设计模式
    学习设计模式
    mybatis从入门到精通(一) 入门
    学习NIO 之 使用方法
    学习 NIO 之 零拷贝
    Java并发
    学习设计模式
  • 原文地址:https://www.cnblogs.com/lindexi/p/12085396.html
Copyright © 2011-2022 走看看