【问题标题】:Is metaprogramming possible in C#?在 C# 中可以进行元编程吗?
【发布时间】:2010-09-19 05:39:30
【问题描述】:

特别是,是否有可能在 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
}

【问题讨论】:

  • 某种寻找 t4 模板 抱歉在 iphone 上无法指向资源。 Scott Hansleman 上周发布了关于它的信息。
  • 试试看script.net;更多信息在 --orbifold.net/default/?p=2457
  • 虽然这在 C# 中是不可能的,但在替代的 .NET 强类型语言中是可能的,例如 BooNemerle
  • 您可以阅读 Kevin Hazzard 和 Jason Bock 在 .NET manning.com/hazzard 中的元编程
  • @Jordão:Boo 是一种非常不同的语言,自从 Jetbrains 雇佣了大脑以来,Nemerle 或多或少已经死了。也许 Script.NET 值得一提。

标签: c# metaprogramming


【解决方案1】:

不,C# 语言不直接支持这种复杂性的元编程。然而,正如@littlegeek 所说,Visual Studio 中包含的Text Template Transformation Toolkit 将允许您实现任何复杂的代码生成。

【讨论】:

  • 没问题 littlegeek;即使没有剪贴板,我也投票支持你击败我 4 小时 :)
  • “文本模板转换工具包”链接已损坏,请改用此链接:wekeroad.com/2008/10/13/…
  • @GrantPeters,现在连这个都坏了
  • @StanislavProkop 我删除了断开的链接并将 Scott Hanselman 的文章提升到了初级。
【解决方案2】:

在 .NET 中可以进行元编程(请参阅编译器编译器、正则表达式、代码 DOM、反射等),但 C# 不具备 模板 元编程功能,因为它没有那种语言特性。

【讨论】:

  • +1 简要而全面地回答问题的各个方面。
【解决方案3】:

大多数人坚持尝试从他们最喜欢的语言内部进行元编程。如果语言不能很好地支持元编程,那就不行了。其他答案观察到 C# 没有。

解决这个问题的一种方法是从语言外部进行元编程,使用 program transformation tools。这样的工具可以解析源代码,并对其进行任意转换(这就是元编程所做的),然后吐出修改后的程序。

如果您有一个可以解析任意语言的通用程序转换系统,那么您就可以在/使用您喜欢的任何语言上进行元编程。 请参阅我们的DMS Software Reengineering Toolkit 了解此类工具,该工具具有适用于 C、C++、Java、C#、COBOL、PHP 和许多其他编程语言的强大前端,并已用于所有这些语言的元编程。

DMS 之所以成功,是因为它提供了一种常规方法和支持基础架构,可以完全访问作为 AST 的程序结构,并且在大多数情况下,附加数据,如符号表、类型信息、控制和数据流分析,所有这些都是执行复杂程序所必需的操纵。

编辑(回应评论):可以应用 DMS 在 C# 上实现 OP 的任务。

【讨论】:

  • -1:很好的答案,但它没有回答这个特定的问题。
  • @Saunders:实际上确实如此,但您需要做一些功课。如果要实现 OP 的特定任务,则需要实现常量折叠程序转换并将它们集中在对 Fibonacci 函数的调用上。我注意到,当没有任何答案都解决了 OP 的具体问题时,你把我的答案搞砸了。
  • 谢谢,您为我的工作指明了正确的方向!
【解决方案4】:

在处理 Java 或 .Net 语言时,在谈论编译时时必须小心。 在这些语言中,您可以执行比 C++ 更强大的元编程(广义上的反射),因为“编译时间”(JIT)可以在“运行时间”之后推迟;)

【讨论】:

    【解决方案5】:

    .NET 泛型和 C++ 模板之间的本质区别在于泛型在运行时是专用的。模板在编译时展开。泛型的动态行为使诸如 Linq、表达式树、Type.MakeGenericType()、语言独立性和代码重用之类的东西成为可能。

    但这是有代价的,例如,您不能在泛型类型参数的值上使用运算符。您不能在 C# 中编写 std::complex 类。并且没有编译时元编程。

    【讨论】:

    • 我根据经验知道模板代码是可以重用的。您所指的所谓“语言独立性”实际上意味着您必须使用符合 .net 的语言…….net 泛型和 c++ 模板都有限制。但这些都不是正确的。
    • 当然,您可以在 C# 中编写复数类(或者更好的是结构),但是对数值类型参数进行计算的模板库很难编写和使用,请参阅 @987654321 @和codeproject.com/KB/cross-platform/BenchmarkCppVsDotNet.aspx
    • “你不能在 C# 中编写 std::complex 类”。在什么意义上?
    • @JonHarrop 从某种意义上说,性能会很糟糕,而且你也会失去编译时的安全性。并且一些与转换相关的部分根本不可能。
    • 1) 重载运算符没有通用约束。因此,您失去了编译时的安全性。 2) 如果没有这些约束,则无法在专业化上选择用户定义的运算符。因此,您需要使用运行时方法生成,并且每当您调用操作员时都会获得委托调用开销。 3) 你不能表达类似“如果T1 可以隐式转换为T2 那么Complex&lt;T1&gt; 应该可以隐式转换为Complex&lt;T2&gt;”。
    【解决方案6】:

    不,元编程在 C# 中是不可能的。

    【讨论】:

      【解决方案7】:

      非常有限的范围内,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
      }
      

      【讨论】:

      • 提问者并没有具体说明他们所说的元编程是什么意思,但我认为可以肯定地说它与你的意思不同。
      • @Anthony,模棱两可的问题的问题是它们会产生不正确或无意的答案。我无法回答这个问题或提供一个可以回答这个问题的答案。只要我在这里,我想我还不如回答:)
      【解决方案8】:

      这将是可能的。观看 Anders Hejlsberg 的 The Future of C# 演讲。

      【讨论】:

      • 你的评论是2009年写的,十年过去了,还是不行。
      【解决方案9】:

      不是按照您的要求,但您可以使用一些旧的 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> {}
      

      我在具有大量子类的库中使用此技术,其中添加新数据成员需要大量样板文件。

      【讨论】:

        猜你喜欢
        • 2010-11-24
        • 2010-09-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-10
        • 1970-01-01
        • 2013-06-06
        • 1970-01-01
        相关资源
        最近更新 更多