.NET升级助手为何将部分Reference转为PackageReference?
.NET Upgrade Assistant转换.csproj时Reference的处理逻辑解析
问题说明
使用.NET Upgrade Assistant将旧格式的.NET Framework项目.csproj转换为SDK-style格式时,出现了三种不同的引用处理结果:
- 部分原
<Reference>标签被转换为<PackageReference> - 部分
<Reference>标签保留原样 - 还有一部分
<Reference>被完全移除
原本认为这些引用都属于.NET Framework,应从本地安装或GAC(全局程序集缓存)引入,疑惑为何会被转为NuGet包引用,且本次示例无C#代码,引用是否被使用不影响转换结果,想了解转换的逻辑依据,以及不同场景下该优先选择NuGet包还是.NET Framework引用。
转换示例
旧格式.csproj
<?xml version="1.0" encoding="utf-8"?> <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <PropertyGroup> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> <ProjectGuid>{4D2709F3-A2AF-4083-AB04-85BB258F9B2F}</ProjectGuid> <OutputType>Exe</OutputType> <RootNamespace>ConsoleAppOldFormat</RootNamespace> <AssemblyName>ConsoleAppOldFormat</AssemblyName> <TargetFrameworkVersion>v4.8</TargetFrameworkVersion> <FileAlignment>512</FileAlignment> <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> <Deterministic>true</Deterministic> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PlatformTarget>AnyCPU</PlatformTarget> <DebugSymbols>true</DebugSymbols> <DebugType>full</DebugType> <Optimize>false</Optimize> <OutputPath>bin\Debug\</OutputPath> <DefineConstants>DEBUG;TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> <PlatformTarget>AnyCPU</PlatformTarget> <DebugType>pdbonly</DebugType> <Optimize>true</Optimize> <OutputPath>bin\Release\</OutputPath> <DefineConstants>TRACE</DefineConstants> <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> <ItemGroup> <Reference Include="System" /> <Reference Include="System.Core" /> <Reference Include="System.Xml.Linq" /> <Reference Include="Microsoft.CSharp" /> <Reference Include="System.Data" /> <Reference Include="System.Net.Http" /> <Reference Include="System.Xml" /> <Reference Include="System.IO" /> <Reference Include="System.Runtime" /> <Reference Include="System.ValueTuple" /> <Reference Include="System.Drawing" /> <Reference Include="System.ComponentModel.Composition" /> <Reference Include="System.DirectoryServices" /> <Reference Include="System.Data.DataSetExtensions" /> </ItemGroup> <ItemGroup> <Compile Include="Program.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> </ItemGroup> <ItemGroup> <None Include="App.config" /> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> </Project>
转换后的SDK-style .csproj
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <TargetFramework>net48</TargetFramework> <OutputType>Exe</OutputType> <GenerateAssemblyInfo>false</GenerateAssemblyInfo> </PropertyGroup> <ItemGroup> <Reference Include="System.IO" /> <Reference Include="System.Runtime" /> <Reference Include="System.ValueTuple" /> </ItemGroup> <ItemGroup> <PackageReference Include="Microsoft.CSharp" Version="4.7.0" /> <PackageReference Include="System.ComponentModel.Composition" Version="9.0.2" /> <PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" /> <PackageReference Include="System.DirectoryServices" Version="9.0.2" /> </ItemGroup> </Project>
转换的逻辑依据
.NET Upgrade Assistant的转换逻辑基于微软对.NET组件的发布策略和SDK-style项目的设计规范:
- 转为PackageReference的组件:比如
Microsoft.CSharp、System.ComponentModel.Composition这类组件,微软已将其作为独立NuGet包发布,这些包同时兼容.NET Framework和现代.NET(如.NET 6/7/8)。使用NuGet引用能更精准地控制版本,避免GAC中版本不一致导致的问题,同时为未来项目升级到跨平台.NET打下基础。 - 保留为Reference的组件:像
System.IO、System.Runtime这类属于.NET Framework的核心基础组件,要么没有对应的独立NuGet包,要么NuGet包是为跨平台场景设计的,但.NET Framework本身已内置完整版本,直接引用本地安装或GAC中的组件更符合.NET Framework项目的运行逻辑。 - 被移除的组件:比如
System、System.Core、System.Data这类是SDK-style项目默认自动引入的.NET Framework核心依赖,SDK会根据<TargetFramework>自动加载这些基础组件,无需显式声明,因此被自动移除。
场景选择建议
优先选择PackageReference的场景
- 组件有官方发布的NuGet包,且项目未来有升级到跨平台.NET的计划
- 需要精确控制组件版本,避免团队协作或部署环境中出现GAC版本冲突
- 依赖的组件在.NET Framework中版本较旧,需要通过NuGet获取更新版本
保留.NET Framework Reference的场景
- 组件是.NET Framework专属,无官方NuGet包(如某些老旧的系统组件)
- 项目无需跨平台,且依赖的.NET Framework版本固定,依赖的组件只能从本地安装目录或GAC获取
- 引用的组件有特殊的系统级依赖,无法通过NuGet包正常运行
内容的提问来源于stack exchange,提问作者tomwaitforitmy
相关产品推荐
相关产品推荐

