温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

如何解决.NET Core/Standard 2.0编译时报“CS0579: Duplicate 'Assem的问题

发布时间:2021-12-06 11:35:07 来源:亿速云 阅读:170 作者:柒染 栏目:大数据

这篇文章给大家介绍如何解决.NET Core/Standard 2.0编译时报“CS0579: Duplicate 'Assem的问题,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

一、缘由

当创建 .NET Core/Standard 2.0项目时,VS不会像.NET Framework项目一样自动生成AssemblyInfo.cs文件。

而且,若是手工在项目中加入以前写好的 AssemblyInfo.cs 文件,编译时会报告“CS0579: Duplicate 'AssemblyFileVersionAttribute' attribute”错误。

查了一下资料,发现是因为“.NET Core/Standard 2.0会自动填写程序集信息”而引起的。

具体来说——

  1. .NET Core/Standard 2.0 推荐在项目属性的“Package”页配置程序集的 版本、描述 等信息。

  2. 编译时,会自动根据“Package”页的配置,生成 “ <项目名> .AssemblyInfo.cs”。其中便使用了 AssemblyFileVersionAttribute 等特性。

  3. 我们的 AssemblyInfo.cs 中也使用 AssemblyFileVersionAttribute 等特性。因为 AssemblyFileVersionAttribute 等特性是不允许重复,于是便报出CS0579错误了。

如何解决.NET Core/Standard 2.0编译时报“CS0579: Duplicate 'Assem的问题

删除自己的 AssemblyInfo.cs,完全使用推荐做法(项目属性的“Package”页),当然是可以解决该问题、使项目能成功编译的。但是该方案的缺点是没有AssemblyInfo.cs,无法再用“利用条件编译控制程序集特性”等技巧。

第二种办法是在 AssemblyInfo.cs 中加上条件编译,若发现是 .NET Core/Standard 2.0(#if NETCOREAPP2_0 || NETSTANDARD2_0)时,便屏蔽掉 AssemblyFileVersionAttribute 等特性。但该方法比较繁琐。

有没有办法“禁止自动生成程序集特性,完全使用自己的AssemblyInfo.cs”呢?

二、解决

查了一下资料,找到了“.NET Core/Standard 2.0 禁止自动生成程序集特性”的办法。就是——修改项目的csproj文件,在PropertyGroup节点内加上“  false  ”

例如修改前是这样的——

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <AssemblyName>ConsoleExample</AssemblyName>
    <RootNamespace>ConsoleExample</RootNamespace>
  </PropertyGroup>

</Project>

修改后变为这样——

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>netcoreapp2.0</TargetFramework>
    <AssemblyName>ConsoleExample</AssemblyName>
    <RootNamespace>ConsoleExample</RootNamespace>
    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
  </PropertyGroup>

</Project>

改好后便会发现不再自动生成 “ <项目名> .AssemblyInfo.cs”了,能使用自己的AssemblyInfo.cs,顺利编译了。

三、深入

3.1 自动生成的机制

“ <项目名> .AssemblyInfo.cs”的内容一般是这样的——

//------------------------------------------------------------------------------
// <auto-generated>
//     This code was generated by a tool.
//     Runtime Version:4.0.30319.42000
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("ConsoleExample")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyDescriptionAttribute("Package Description")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")]
[assembly: System.Reflection.AssemblyProductAttribute("ConsoleExample")]
[assembly: System.Reflection.AssemblyTitleAttribute("ConsoleExample")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
// Generated by the MSBuild WriteCodeFragment class.

上面这段自动生成的代码,实际上是由 c:\Program Files\dotnet\sdk\2.0.0\Sdks\Microsoft.NET.Sdk\build\Microsoft.NET.GenerateAssemblyInfo.targets 控制的。该文件的内容是——

<!--
***********************************************************************************************
Microsoft.NET.GenerateAssemblyInfo.targets

WARNING:  DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
          created a backup copy.  Incorrect changes to this file will make it
          impossible to load or build your projects from the command-line or the IDE.

Copyright (c) .NET Foundation. All rights reserved. 
***********************************************************************************************
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <!--
    ============================================================
                                    GenerateAssemblyInfo

    Generates assembly info source to intermediate directory
    ============================================================
    -->
  <PropertyGroup>
    <MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
    <GeneratedAssemblyInfoFile Condition="'$(GeneratedAssemblyInfoFile)' ==''">$(IntermediateOutputPath)$(MSBuildProjectName).AssemblyInfo$(DefaultLanguageSourceExtension)</GeneratedAssemblyInfoFile>
    <GenerateAssemblyInfo Condition="'$(GenerateAssemblyInfo)' == ''">true</GenerateAssemblyInfo>
  </PropertyGroup>

  <PropertyGroup Condition="'$(GenerateAssemblyInfo)' == 'true'">
    <GenerateAssemblyCompanyAttribute Condition="'$(GenerateAssemblyCompanyAttribute)' == ''">true</GenerateAssemblyCompanyAttribute>
    <GenerateAssemblyConfigurationAttribute Condition="'$(GenerateAssemblyConfigurationAttribute)' == ''">true</GenerateAssemblyConfigurationAttribute>
    <GenerateAssemblyCopyrightAttribute Condition="'$(GenerateAssemblyCopyrightAttribute)' == ''">true</GenerateAssemblyCopyrightAttribute>
    <GenerateAssemblyDescriptionAttribute Condition="'$(GenerateAssemblyDescriptionAttribute)' == ''">true</GenerateAssemblyDescriptionAttribute>
    <GenerateAssemblyFileVersionAttribute Condition="'$(GenerateAssemblyFileVersionAttribute)' == ''">true</GenerateAssemblyFileVersionAttribute>
    <GenerateAssemblyInformationalVersionAttribute Condition="'$(GenerateAssemblyInformationalVersionAttribute)' == ''">true</GenerateAssemblyInformationalVersionAttribute>
    <GenerateAssemblyProductAttribute Condition="'$(GenerateAssemblyProductAttribute)' == ''">true</GenerateAssemblyProductAttribute>
    <GenerateAssemblyTitleAttribute Condition="'$(GenerateAssemblyTitleAttribute)' == ''">true</GenerateAssemblyTitleAttribute>
    <GenerateAssemblyVersionAttribute Condition="'$(GenerateAssemblyVersionAttribute)' == ''">true</GenerateAssemblyVersionAttribute>
    <GenerateNeutralResourcesLanguageAttribute Condition="'$(GenerateNeutralResourcesLanguageAttribute)' == ''">true</GenerateNeutralResourcesLanguageAttribute>
  </PropertyGroup>

  <!-- 
    Note that this must run before every invocation of CoreCompile to ensure that all compiler
    runs see the generated assembly info. There is at least one scenario involving Xaml 
    where CoreCompile is invoked without other potential hooks such as Compile or CoreBuild,
    etc., so we hook directly on to CoreCompile. Furthermore, we  must run *after* 
    PrepareForBuild to ensure that the intermediate directory has been created.
  -->
  <Target Name="GenerateAssemblyInfo"
          BeforeTargets="CoreCompile"
          DependsOnTargets="PrepareForBuild;CoreGenerateAssemblyInfo"
          Condition="'$(GenerateAssemblyInfo)' == 'true'" />

  <Target Name="GetAssemblyAttributes"
          DependsOnTargets="GetAssemblyVersion">
    <ItemGroup>
      <AssemblyAttribute Include="System.Reflection.AssemblyCompanyAttribute" Condition="'$(Company)' != '' and '$(GenerateAssemblyCompanyAttribute)' == 'true'">
        <_Parameter1>$(Company)</_Parameter1>
      </AssemblyAttribute>
      <AssemblyAttribute Include="System.Reflection.AssemblyConfigurationAttribute" Condition="'$(Configuration)' != '' and '$(GenerateAssemblyConfigurationAttribute)' == 'true'">
        <_Parameter1>$(Configuration)</_Parameter1>
      </AssemblyAttribute>
      <AssemblyAttribute Include="System.Reflection.AssemblyCopyrightAttribute" Condition="'$(Copyright)' != '' and '$(GenerateAssemblyCopyrightAttribute)' == 'true'">
        <_Parameter1>$(Copyright)</_Parameter1>
      </AssemblyAttribute>
      <AssemblyAttribute Include="System.Reflection.AssemblyDescriptionAttribute" Condition="'$(Description)' != '' and '$(GenerateAssemblyDescriptionAttribute)' == 'true'">
        <_Parameter1>$(Description)</_Parameter1>
      </AssemblyAttribute>
      <AssemblyAttribute Include="System.Reflection.AssemblyFileVersionAttribute" Condition="'$(FileVersion)' != '' and '$(GenerateAssemblyFileVersionAttribute)' == 'true'">
        <_Parameter1>$(FileVersion)</_Parameter1>
      </AssemblyAttribute>
      <AssemblyAttribute Include="System.Reflection.AssemblyInformationalVersionAttribute" Condition="'$(InformationalVersion)' != '' and '$(GenerateAssemblyInformationalVersionAttribute)' == 'true'">
        <_Parameter1>$(InformationalVersion)</_Parameter1>
      </AssemblyAttribute>
      <AssemblyAttribute Include="System.Reflection.AssemblyProductAttribute" Condition="'$(Product)' != '' and '$(GenerateAssemblyProductAttribute)' == 'true'">
        <_Parameter1>$(Product)</_Parameter1>
      </AssemblyAttribute>
      <AssemblyAttribute Include="System.Reflection.AssemblyTitleAttribute" Condition="'$(AssemblyTitle)' != '' and '$(GenerateAssemblyTitleAttribute)' == 'true'">
        <_Parameter1>$(AssemblyTitle)</_Parameter1>
      </AssemblyAttribute>
      <AssemblyAttribute Include="System.Reflection.AssemblyVersionAttribute" Condition="'$(AssemblyVersion)' != '' and '$(GenerateAssemblyVersionAttribute)' == 'true'">
        <_Parameter1>$(AssemblyVersion)</_Parameter1>
      </AssemblyAttribute>
      <AssemblyAttribute Include="System.Resources.NeutralResourcesLanguageAttribute" Condition="'$(NeutralLanguage)' != '' and '$(GenerateNeutralResourcesLanguageAttribute)' == 'true'">
        <_Parameter1>$(NeutralLanguage)</_Parameter1>
      </AssemblyAttribute>
    </ItemGroup>
  </Target>

  <!-- 
    To allow version changes to be respected on incremental builds (e.g. through CLI parameters),
    create a hash of all assembly attributes so that the cache file will change with the calculated
    assembly attribute values and msbuild will then execute CoreGenerateAssembly to generate a new file.
  -->
  <Target Name="CreateGeneratedAssemblyInfoInputsCacheFile"
          DependsOnTargets="GetAssemblyAttributes">
    <PropertyGroup>
      <GeneratedAssemblyInfoInputsCacheFile>$(IntermediateOutputPath)$(MSBuildProjectName).AssemblyInfoInputs.cache</GeneratedAssemblyInfoInputsCacheFile>
    </PropertyGroup>

    <Hash ItemsToHash="@(AssemblyAttribute->'%(Identity)%(_Parameter1)')">
      <Output TaskParameter="HashResult" PropertyName="_AssemblyAttributesHash" />
    </Hash>

    <WriteLinesToFile Lines="$(_AssemblyAttributesHash)" File="$(GeneratedAssemblyInfoInputsCacheFile)" Overwrite="True" WriteOnlyWhenDifferent="True" />
    
    <ItemGroup>
      <FileWrites Include="$(GeneratedAssemblyInfoInputsCacheFile)" />
    </ItemGroup>
  </Target>

  <Target Name="CoreGenerateAssemblyInfo"
          Condition="'$(Language)'=='VB' or '$(Language)'=='C#'"
          DependsOnTargets="CreateGeneratedAssemblyInfoInputsCacheFile"
          Inputs="$(GeneratedAssemblyInfoInputsCacheFile)"
          Outputs="$(GeneratedAssemblyInfoFile)">
    <ItemGroup>
      <!-- Ensure the generated assemblyinfo file is not already part of the Compile sources, as a workaround for https://github.com/dotnet/sdk/issues/114 -->
      <Compile Remove="$(GeneratedAssemblyInfoFile)" />
    </ItemGroup>

    <WriteCodeFragment AssemblyAttributes="@(AssemblyAttribute)" Language="$(Language)" OutputFile="$(GeneratedAssemblyInfoFile)">
      <Output TaskParameter="OutputFile" ItemName="Compile" />
      <Output TaskParameter="OutputFile" ItemName="FileWrites" />
    </WriteCodeFragment>
  </Target>


  <!--
    ==================================================================
                                            GetAssemblyVersion

    Parses the nuget package version set in $(Version) and returns
    the implied $(AssemblyVersion) and $(FileVersion).

    e.g.:
        <Version>1.2.3-beta.4</Version>

    implies:
        <AssemblyVersion>1.2.3</AssemblyVersion>
        <FileVersion>1.2.3</FileVersion>

    Note that if $(AssemblyVersion) or $(FileVersion) are are already set, it
    is considered an override of the default inference from $(Version) and they
    are left unchanged by this target.
    ==================================================================
  -->
  <Target Name="GetAssemblyVersion">
    <GetAssemblyVersion Condition="'$(AssemblyVersion)' == ''" NuGetVersion="$(Version)">
      <Output TaskParameter="AssemblyVersion" PropertyName="AssemblyVersion" />
    </GetAssemblyVersion>
    
    <PropertyGroup>
      <FileVersion Condition="'$(FileVersion)' == ''">$(AssemblyVersion)</FileVersion>
      <InformationalVersion Condition="'$(InformationalVersion)' == ''">$(Version)</InformationalVersion>
    </PropertyGroup>
  </Target>

</Project>

3.2 部分自动生成

弄清楚机制后,我们可以做成部分自动生成的。即部分程序集特性自动生成,另外一部分来自我们自己的AssemblyInfo.cs。

具体办法是修改项目的csproj文件,在PropertyGroup节点内加上“  false  ”等内容,而不用GenerateAssemblyInfo。

例如——

<PropertyGroup>
  <TargetFramework>netcoreapp1.1</TargetFramework>
  <OutputType>Exe</OutputType>
  <GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
  <GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
  <GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
</PropertyGroup>

GenerateAssemblyConfigurationAttribute这样的参数名详见 Microsoft.NET.GenerateAssemblyInfo.targets

关于如何解决.NET Core/Standard 2.0编译时报“CS0579: Duplicate 'Assem的问题就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI