将参数传递到从 C# 中的 dll 检索的 T4 运行时模板

Passing parameter into T4 runtime template retrieved from a dll in C#

我有一个 DLL,它有一个 T4 运行时模板和一个 class,它通过一个方法返回该模板的实例(模板名称是 Query.tt,它生成了 class Query.cs):

来自 dll 的模板:

<#@ template language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ template debug="true" #>
<#@ parameter name="TestObj" type="TemplateDLL.Class2" #>

Hellow <#= this.TestObj.s #>!
Hellow <#= this.TestObj.x #>!

Class 来自 dll:

namespace TemplateDLL
{
   public class Class1
   {
       public Query getQueryTemplate()
       {
           return new Query();
       } 
   }
}

我正在使用 Reflections 将此 dll 加载到另一个项目中:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;

namespace TestDynTemplate2
{
    class Program
    {
        static void Main(string[] args)
        {
           var DLL = Assembly.LoadFile(@"D:\somedllpath\TemplateDLL.dll");

           dynamic c =  Activator.CreateInstance(DLL.GetType("TemplateDLL.Class1"));

           var templateInstance = c.getQueryTemplate();

           TemplateDLL.Class2 c2 = new TemplateDLL.Class2();
           c2.x = 3;
           c2.s = "cdfafdafa";


          templateInstance.Session = new Dictionary<string, object>();
          templateInstance.Session.Add("TestObj", c2);
          templateInstance.Initialize();

          var generatedCode = templateInstance.TransformText();

          Console.WriteLine(generatedCode);
        }
    }
}

我在两个项目(int dll 项目和 dll 调用项目)中也有一个 class (TemplateDLL.Class2) 的定义,我实例化了它(在调用 dll 中) project) 然后我将实例传递给生成模板的 dll 函数。我传递的对象用于 dll 中的模板。

namespace TemplateDLL
{
    class Class2
    {
        public int x;
        public string s;
    }
}

一切正常,直到对象在模板中使用时抛出 System.InvalidCastException:[A]TemplateDLL。Class2 无法转换为 [B]TemplateDLL。Class2。它告诉我 A 型和 B 型起源不同。

如何才能使这项工作?我是 c# 和 T4 的新手。

在 C# 中(通常在 .NET 中)相同的 定义 并不意味着 相同的 class

Class2 在程序集 A 中声明的 Class2 和在程序集 B 中声明的 Class2 是完全不同的 classes(碰巧共享相同的命名空间和 class 名称)因为 class 由其全名和程序集定义(其中还包括处理器体系结构和 public 密钥,请参阅 GetType() on MSDN 了解更多详细信息)。

您必须在声明该类型或从一种类型复制(例如通过反射)到另一种类型的地方共享程序集。像这样:

var instanceInBType = instanceInB.GetType();
foreach (var fieldInA in instanceFromA.GetType().GetFields())
{
    var fieldInB = instanceInBType.GetField(field.Name);
    var valueInA = fieldInA.GetValue(instanceFromA);

    fieldInB.SetValue(instanceInB, valueInA);
}

实际上你必须接受一个 generic object 参数 (instanceFromA),创建一个局部变量 instanceInB 并逐字段复制从A到B。当然共享类型定义肯定更好...