溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何解決.NET Core/Standard 2.0編譯時報“CS0579: Duplicate 'Assem的問題

發(fā)布時間:2021-12-06 11:35:07 來源:億速云 閱讀:162 作者:柒染 欄目:大數(shù)據(jù)

這篇文章給大家介紹如何解決.NET Core/Standard 2.0編譯時報“CS0579: Duplicate 'Assem的問題,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

一、緣由

當創(chuàng)建 .NET Core/Standard 2.0項目時,VS不會像.NET Framework項目一樣自動生成AssemblyInfo.cs文件。

而且,若是手工在項目中加入以前寫好的 AssemblyInfo.cs 文件,編譯時會報告“CS0579: Duplicate 'AssemblyFileVersionAttribute' attribute”錯誤。

查了一下資料,發(fā)現(xiàn)是因為“.NET Core/Standard 2.0會自動填寫程序集信息”而引起的。

具體來說——

  1. .NET Core/Standard 2.0 推薦在項目屬性的“Package”頁配置程序集的 版本、描述 等信息。

  2. 編譯時,會自動根據(jù)“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 中加上條件編譯,若發(fā)現(xiàn)是 .NET Core/Standard 2.0(#if NETCOREAPP2_0 || NETSTANDARD2_0)時,便屏蔽掉 AssemblyFileVersionAttribute 等特性。但該方法比較繁瑣。

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

二、解決

查了一下資料,找到了“.NET Core/Standard 2.0 禁止自動生成程序集特性”的辦法。就是——修改項目的csproj文件,在PropertyGroup節(jié)點內加上“  false  ”

例如修改前是這樣的——

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

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

</Project>

修改后變?yōu)檫@樣——

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

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

</Project>

改好后便會發(fā)現(xiàn)不再自動生成 “ <項目名> .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節(jié)點內加上“  false  ”等內容,而不用GenerateAssemblyInfo。

例如——

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

GenerateAssemblyConfigurationAttribute這樣的參數(shù)名詳見 Microsoft.NET.GenerateAssemblyInfo.targets 。

關于如何解決.NET Core/Standard 2.0編譯時報“CS0579: Duplicate 'Assem的問題就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內容。

AI