• Roslyn如何引用某个文件夹所有文件作为链接?
  • 发布于 2个月前
  • 206 热度
    0 评论
  • 王晶
  • 0 粉丝 41 篇博客
  •   
在 SDK 格式的项目文件可以通过简单代码引用某个文件夹里面指定后缀的文件作为项目文件。例如我想要引用相对于 csproj 的上一层文件夹里面的 doubi 文件夹里面的所有 cs 文件,作为链接引用的方法,可以使用下面代码:
  <ItemGroup>
    <Compile Include="..\doubi\*.cs" Link="duidaima.com\%(FileName)%(Extension)" />
  </ItemGroup>
上面代码用到了 FileName 可以替换每一项的文件名,加上 Extension 就能表示路径。按照上面的代码,其实后缀名也是根据引用的文件自动添加,那么如何添加某个文件夹里面的所有 png 文件。差不多的逻辑也就能写出添加某个项目里面的所有 png 文件。
  <ItemGroup>
    <Content Include="..\Tool.UWP\Assets\*.png" Link="Assets\%(FileName)%(Extension)" />
  </ItemGroup>
如果想要引用文件夹里面的所有内容,即使这些内容在文件夹的文件夹里面,也就是不在顶层文件夹,可以这样写
  <ItemGroup>
    <Content Include="..\Tool.UWP\Assets\**\*.png" Link="Assets\%(FileName)%(Extension)" />
  </ItemGroup>
可以看到上面代码添加了 **\*.png 其中的 ** 表示任意一层文件夹。而有时候包含了 obj 等不期望加入的文件,可以通过 Exclude 输入,请看以下示例:
Exclude="..\Tool.UWP\obj\**\*;"
大概的代码如下:
  <ItemGroup>
    <Content Include="..\Tool.UWP\Assets\**\*.png" Exclude="..\Tool.UWP\obj\**\*;..\Tool.UWP\Foo\**\*" />
  </ItemGroup>
如果只是期望引用某个文件夹里面的某几个文件,可以参阅 如何在 MSBuild 中正确使用 % 来引用每一个项(Item)中的元数据 - walterlv 的写法。先写一个自定义项用来接收需要特殊指定的文件,接着再写一个中转使用的自定义项来拼接,最后加入到引用即可。如以下代码:
  <ItemGroup>
    <FooAddFileName Include="1.png"/>
    <FooAddFileName Include="2.png"/>
    <FooAddFileName Include="3.png"/>

    <__FooAddFileName Include="@(FooAddFileName)">
      <ReferenceFilePath>..\Tool.UWP\Assets\%(Identity)</ReferenceFilePath>
    </__FooAddFileName>

    <Content Include="@(__FooAddFileName->'%(ReferenceFilePath)')" Link="Assets\%(FileName)%(Extension)" />
  </ItemGroup>
以上代码自定义了为 FooAddFileName 的自定义项用来接收需要特殊指定的文件。如以上代码指定了 1.png 等特殊几个文件。接着定义了名为 __FooAddFileName 的自定义项用来中转,凭借上文件夹路径。最后再加入引用。

如果不想让加入的项目在 VisualStudio 里可见,可加上 Visible="False" 属性,如以下代码:
<!-- 堆代码 duidaima.com -->
  <ItemGroup>
    <None Include="..\MauiApp\bin\Debug\net6.0\**\*" CopyToOutputDirectory="PreserveNewest" Visible="False"></None>
  </ItemGroup>
如需保持相对路径关系,可采用 %(RecursiveDir) 属性,如以下例子。
<Compile Include="..\..\DocumentFormat.OpenXml.Flatten\src\DocumentFormat.OpenXml.Flatten\**\*.cs" Exclude="**\bin\**\*.cs;**\obj\**\*.cs" Link="DocumentFormat.OpenXml.Flatten\%(RecursiveDir)\%(FileName)%(Extension)" />
如果只是为了放入到某个文件夹里面,可以使用 LinkBase 特性辅助,例如全部放入到 Shared 文件夹,例子如下:
<ItemGroup>
  <Content Include="..\Extras\**\*.cs" LinkBase="Shared"/>
</ItemGroup
通过这个方法可以将原本一个大的项目,才分为多个小的项目,每个小项目独立,但是最终打包的项目将通过此 方式引用所有的小项目。同时打包的时候不仅主项目会打包,每个小的项目都可以独立打包,这样做的优势是可以提升每个小项目的内聚和降低项目之间的耦合。

我现在将很多基础的工具库都用此方式管理,我将一个工具库拆分为很多个小的工具库,每个工具库只包含很小的功能,但是同时我也创建一个主项目,这个主项目里面只放很少的代码,主要代码都是通过本文的方式引用所有小工具库的代码,这样打包出来的主项目是包含全部功能的。但是这个主项目的大小居然有3M这么大了,里面全部都是代码,很多项目里面根本不需要用到这么大的工具项目,于是这些项目就可以使用小的工具库。

如果此时我需要生成不同的平台的库呢?例如某个工具库我只是支持 .NET Framework 的,某个工具库我只支持 WPF 的。

此时通过宏定义的方式就可以让合并到一起的主项目按照输出的不同的 NuGet 库添加不同的代码

另外我推荐使用 SourceYard 的方式制作源代码包,这样每个小的工具库被引用的时候是通过源代码被引用,这样就不会添加额外的引用文件

添加额外的引用文件将会降低软件的启动性能,详细测试请看 C# 程序集数量对软件启动性能的影响

如何使用 SourceYard 做源代码包请看 SoureYard 官方开源项目

用户评论