为了给大家一些背景,我正在开发一个针对CLR的新编程语言,名为“Liberty”。该语言的一个特点是其能够定义“类型构造器(type constructors)”,这些方法由编译器在编译时执行,并生成类型作为输出。它们是泛型的一种概括(该语言确实具有正常的泛型),并允许编写以下代码(用“Liberty”语法):
var t as tuple<i as int, j as int, k as int>;
t.i = 2;
t.j = 4;
t.k = 5;
“tuple” 的定义如下:
public type tuple(params variables as VariableDeclaration[]) as TypeDeclaration
{
//...
}
在这个例子中,类型构造函数
tuple
提供了类似于VB和C#中的匿名类型的东西。但是,与匿名类型不同,“元组”具有名称并且可以在公共方法签名中使用。这意味着我需要一种方法来使最终由编译器发出的类型可在多个程序集之间共享。例如,我想要在程序集A中定义的tuple<x as int>
最终成为与在程序集B中定义的tuple<x as int>
相同的类型。当然,问题在于程序集A和程序集B将在不同的时间编译,这意味着它们都将发出自己不兼容的版本的元组类型。我研究了一些“类型擦除”的方法来解决这个问题,这样我就会有一个共享库,其中包含许多这样的类型(这是“Liberty”语法):class tuple<T>
{
public Field1 as T;
}
class tuple<T, R>
{
public Field2 as T;
public Field2 as R;
}
然后只需将 i、j 和 k 的访问重定向到
Field1
、Field2
和 Field3
即可。但这并不是一个可行的选择。这意味着在编译时,tuple<x as int>
和 tuple<y as int>
将成为不同的类型,而在运行时,它们将被视为相同的类型。这会导致许多问题,例如相等性和类型识别。对我来说,这是一个过于泄露的抽象概念。其他可能的选择是使用“状态包对象”。然而,使用状态包将破坏语言中“类型构造函数”的全部目的。其想法是启用“自定义语言扩展”,以生成编译器可以进行静态类型检查的新类型。
在 Java 中,可以使用自定义类加载器来实现此操作。基本上,使用元组类型的代码可以在未在磁盘上定义该类型的情况下发出。然后可以定义一个自定义“类加载器”,在运行时动态生成元组类型。这将允许编译器内部进行静态类型检查,并统一跨编译边界的元组类型。
然而,不幸的是,CLR 不支持自定义类加载。CLR 中的所有加载都是在程序集级别完成的。可以为每个“构造类型”定义一个单独的程序集,但这将很快导致性能问题(具有只包含一个类型的许多程序集将使用过多的资源)。
因此,我想知道:
是否可能在 .NET 中模拟类似于 Java 类加载器的东西,在其中可以发出对不存在类型的引用,然后在需要使用它的代码运行之前在运行时动态生成对该类型的引用?
注意:
*实际上我已经知道了问题的答案,我会在下面提供答案。然而,我花了大约3天的时间进行研究,并进行了相当多的 IL 黑客攻击,以便提出解决方案。我想如果其他人遇到了同样的问题,将其记录在这里是个好主意。*
privatescope
和private hidebysig
的区别在哪里? - Dmitri Nesteruk