在 C# 中是否可以进行元编程
本文关键字:编程 是否 | 更新日期: 2023-09-27 17:47:23
特别是,是否可以在编译时在 C# 中执行与此 C++ 代码类似的代码?
template <int N>
struct Factorial
{
enum { value = N * Factorial<N - 1>::value };
};
template <>
struct Factorial<0>
{
enum { value = 1 };
};
// Factorial<4>::value == 24
// Factorial<0>::value == 1
void foo()
{
int x = Factorial<4>::value; // == 24
int y = Factorial<0>::value; // == 1
}
元编程在 .NET 中是可能的(请参阅编译器编译器、正则表达式、代码 DOM、反射等),但 C# 无法进行模板元编程,因为它没有该语言功能。
不,C# 语言不直接支持这种复杂性的元编程。 但是,正如@littlegeek所说,Visual Studio附带的文本模板转换工具包将允许您实现任何复杂的代码生成。
大多数人坚持尝试从他们最喜欢的语言中进行元编程。 如果语言不能很好地支持元编程,这是行不通的;其他答案观察到 C# 没有。
解决此问题的一种方法是从语言外部进行元编程,使用程序转换工具。 这些工具可以解析源代码,并对其执行任意转换(这就是元编程所做的),然后吐出修改后的程序。
如果你有一个通用的程序转换系统,可以解析任意语言,那么你就可以用任何你喜欢的语言进行元编程。请参阅我们的DMS软件再造工具包,了解此类工具,该工具具有强大的前端,适用于C,C++,Java,C#,COBOL,PHP和许多其他编程语言,并且已用于所有这些语言的元编程。
DMS之所以成功,是因为它提供了一种常规方法和支持基础设施,用于完全访问作为AST的程序结构,并且在大多数情况下,附加数据(如符号表,类型信息,控制和数据流分析)都是执行复杂程序操作所必需的。
编辑(回应评论):可以应用 DMS 在 C# 上实现 OP 的任务。
在处理Java或.Net语言时,在谈论编译时时必须小心。在这些语言中,您可以执行比C++更强大的元编程(在广义上 - 反射),因为"编译时间"(JIT)可以在"运行时";)之后推迟
.NET 泛型和C++模板之间的本质区别在于泛型专用于运行时。 模板在编译时展开。 泛型的动态行为使得Linq、表达式树、Type.MakeGenericType()、语言独立性和代码重用成为可能。
但是有代价的,例如,您不能对泛型类型参数的值使用运算符。 不能用 C# 编写 std::complex 类。 并且没有编译时元编程。
不,元编程在 C# 中是不可能的。
在非常有限的程度上,C#可以被解释为元编程。 但实际上,这只不过是过载分辨率。 称之为元编程真的很牵强。
例:
static string SomeFunc<T>(T value) {
return "Generic";
}
static string SomeFunc(int value) {
return "Non-Generic";
}
static void Example() {
SomeFunc(42); // Non-Generic
SomeFunc((object)42); // Generic
}
这将是可能的。观看 Anders Hejlsberg 的 The Future of C# 演讲。
不是你要求的方式,但你可以使用一些旧的C++技巧来生成静态指定特征的类:
abstract class Integer
{
public abstract int Get { get; }
}
public class One : Integer { public override int Get { return 1; } } }
public class Two : Integer { public override int Get { return 2; } } }
public class Three : Integer { public override int Get { return 3; } } }
public class FixedStorage<T, N> where N : Integer, new()
{
T[] storage;
public FixedStorage()
{
storage = new T[new N().Get];
}
public T Get(int i)
{
return storage[i];
}
}
使用此功能,可以定义空间类:
public class Vector3 : FixedStorage<float, Three> {}
public class Vector2 : FixedStorage<float, Two> {}
public class GridCell : FixedStorage<int, Two> {}
我在具有许多子类的库中使用此技术,其中添加新的数据成员需要大量样板文件。