You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:在T4模板中加载.NET 8程序集时的依赖缺失与编译错误解决

求助:在T4模板中加载.NET 8程序集时的依赖缺失与编译错误解决

问题背景

我之前用T4模板在.NET Framework 4.8环境下正常解析程序集,但现在要加载一个.NET 8的类库(LibToLoad.dll)时遇到了麻烦:

  1. 直接加载时抛出FileNotFoundException,提示找不到System.Runtime, Version=8.0.0.0
  2. 尝试引入EF的工具文件(EF.Utility.CS.ttinclude/EF6.Utility.CS.ttinclude)要么无效,要么引发新的编译错误(CS0103: The name 'ArgumentNotNull' does not exist in the current context)

我的T4模板代码:

<#@ template language="C#" debug="false" hostspecific="true" #>
<#@ output extension=".g.cs" #>
<#@ include file="EF.Utility.CS.ttinclude" #>
<#@ assembly name="SOME_PATH\net8.0\LibToLoad.dll" #>
<#
var baseType = typeof(LibToLoad.BaseClass);
var asmQN = baseType.AssemblyQualifiedName;
// var code = new CodeGenerationTools(this); // 后续想使用的EF工具类
#>

要加载的.NET 8类库的csproj:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
  </PropertyGroup>
</Project>

类代码:

namespace LibToLoad {
    public abstract class BaseClass { }
    public partial class MyClass1 : BaseClass {
        public System.Guid Uid;
    }
}

问题根源

Visual Studio默认的T4模板引擎是基于**.NET Framework**的,而.NET 8的程序集依赖的是.NET Core/5+的共享框架体系,两者的依赖加载机制不兼容:

  • .NET Framework的程序集加载器无法识别.NET 8的System.Runtime这类核心库(.NET Framework自身的基础依赖和.NET Core完全不同)
  • 旧版EF的*.Utility.CS.ttinclude是为.NET Framework+EF设计的,和.NET 8的环境不兼容,依赖的内部方法(比如ArgumentNotNull)在当前上下文不存在

解决方案

方案1:在.NET Framework的T4引擎中手动处理程序集解析

既然默认T4引擎是.NET Framework的,我们可以通过注册程序集解析回调,手动加载.NET 8的依赖库:

修改你的T4模板如下:

<#@ template language="C#" debug="true" hostspecific="true" #>
<#@ output extension=".g.cs" #>
<#@ assembly name="System.IO" #>
<#@ assembly name="System.Runtime.Loader" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Reflection" #>
<#
// 注册程序集解析回调,手动加载.NET 8的依赖
AppDomain.CurrentDomain.AssemblyResolve += (sender, args) => {
    var assemblyName = new AssemblyName(args.Name);
    // 1. 先尝试从你的LibToLoad输出目录加载依赖
    var libOutputPath = @"SOME_PATH\net8.0"; // 替换成你的LibToLoad的实际输出路径
    var libDependencyPath = Path.Combine(libOutputPath, $"{assemblyName.Name}.dll");
    if (File.Exists(libDependencyPath))
    {
        return Assembly.LoadFrom(libDependencyPath);
    }

    // 2. 如果找不到,从.NET 8的共享框架目录加载
    var dotNet8InstallPath = Path.Combine(
        Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
        "dotnet", "shared", "Microsoft.NETCore.App", "8.0.0" // 替换成你安装的.NET 8具体版本号
    );
    var frameworkDependencyPath = Path.Combine(dotNet8InstallPath, $"{assemblyName.Name}.dll");
    if (File.Exists(frameworkDependencyPath))
    {
        return Assembly.LoadFrom(frameworkDependencyPath);
    }

    return null;
};

// 手动加载你的.NET 8程序集(不要用<#@ assembly #>指令)
var libAssemblyPath = Path.Combine(libOutputPath, "LibToLoad.dll");
var targetAssembly = Assembly.LoadFrom(libAssemblyPath);
var baseType = targetAssembly.GetType("LibToLoad.BaseClass");
var asmQN = baseType.AssemblyQualifiedName;

// 如果你需要类似EF的CodeGenerationTools,自己实现简易版本或用CodeDom
// 示例:自己实现参数检查(替代EF的ArgumentNotNull)
void ArgumentNotNull(object value, string paramName)
{
    if (value == null)
        throw new ArgumentNullException(paramName);
}
#>

方案2:改用.NET 8原生的T4引擎(推荐)

如果你的项目已经全面转向.NET 8,更彻底的方法是使用.NET 8的T4引擎来运行模板,完全避开.NET Framework的兼容问题:

  1. 创建一个新的SDK风格的.NET 8类库项目(用来承载T4模板)
  2. 安装NuGet包:Microsoft.VisualStudio.TextTemplating.MSBuild(版本尽量和你的VS版本匹配,比如17.8.x)
  3. 在项目的csproj中添加以下配置,让MSBuild用.NET 8引擎编译T4模板:
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.VisualStudio.TextTemplating.MSBuild" Version="17.8.3" PrivateAssets="all" />
    <TextTemplate Include="**\*.tt" />
  </ItemGroup>

  <Target Name="TransformTemplates" BeforeTargets="Build">
    <MSBuild 
      Projects="$(MSBuildProjectFile)" 
      Targets="TransformAllT4Templates" 
      Properties="TextTemplatingEngine=Core" />
  </Target>
</Project>
  1. 将你的T4模板文件添加到这个项目中,直接加载.NET 8程序集即可,无需额外处理依赖:
<#@ template language="C#" debug="true" hostspecific="true" #>
<#@ output extension=".g.cs" #>
<#@ assembly name="SOME_PATH\net8.0\LibToLoad.dll" #>
<#@ import namespace="LibToLoad" #>
<#
var baseType = typeof(BaseClass);
var asmQN = baseType.AssemblyQualifiedName;
// 现在可以正常使用反射或EF的.NET 8工具类
#>

方案3:让LibToLoad兼容.NET Framework和.NET 8(可选)

如果你愿意修改LibToLoad的源码,可以让它同时支持.NET Framework 4.8和.NET 8,这样T4模板(.NET Framework引擎)可以直接加载兼容版本:
修改LibToLoad的csproj:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFrameworks>net8.0;net48</TargetFrameworks>
  </PropertyGroup>
</Project>

然后T4模板中加载net48版本的LibToLoad.dll,这样就不会有.NET Core依赖的问题了。


关于EF工具类的替代

旧版EF的CodeGenerationTools等工具是为.NET Framework设计的,在.NET 8环境下建议替换为:

  • 原生的System.CodeDom API生成代码
  • 使用Roslyn(Microsoft.CodeAnalysis NuGet包)进行更灵活的代码分析与生成

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 08:19:34