web-dev-qa-db-ja.com

C#でメタプログラミングは可能ですか?

特に、この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
}
37
Brian R. Bondy

いいえ、この複雑さのメタプログラミングは、C#言語では直接サポートされていません。ただし、 @ littlegeek と述べたように、 Text Template Transformation Toolkit Visual Studioに含まれていると、複雑なコード生成を実現できます。

31
Jacob Krall

メタプログラミングは.NETで可能です(コンパイラコンパイラ、正規表現、コードDOM、リフレクションなどを参照)が、C#にはその言語機能がないため、テンプレートメタプログラミングはできません。

27
Jon Harrop

ほとんどの人は、好きな言語の中からメタプログラミングを試みることを主張します。言語がメタプログラミングをうまくサポートしていない場合、それは機能しません。他の回答では、C#はそうではないことが観察されています。

これを回避する方法は、 プログラム変換ツール を使用して、言語のoutsideからメタプログラミングを行うことです。このようなツールは、ソースコードを解析し、その上で任意の変換を実行して(メタプログラミングがとにかく行うことです)、改訂されたプログラムを吐き出すことができます。

任意の言語を解析できる汎用プログラム変換システムがある場合は、好きな言語でメタプログラミングを行うことができます。 C、C++、Java、C#、COBOL、PHPおよび他の多くのプログラミング用の堅牢なフロントエンドを備えたツールについては、 DMS Software Reengineering Toolkit を参照してください。言語であり、これらすべてのメタプログラミングに使用されています。

DMSは、ASTとしてプログラム構造に完全にアクセスするための通常の方法とサポートインフラストラクチャを提供し、ほとんどの場合、高度なプログラム操作を行うために必要なシンボルテーブル、型情報、制御、データフロー分析などの追加データを提供するため成功します。

編集(コメントへの応答):C#でOPのタスクを実装するためにDMSを適用できます。

7
Ira Baxter

Javaまたは.Net言語を扱うときは、コンパイル時について話すときは注意が必要です。これらの言語では、C++よりも強力なメタプログラミング(広義には-リフレクション-)を実行できます。 「コンパイル時間」(JIT)は「実行時間」の後に延期できるという事実;)

6
thAAAnos

.NETGenericsとC++ Templatesの本質的な違いは、ジェネリックスは実行時に特殊化されることです。テンプレートはコンパイル時に展開されます。ジェネリックスの動的な動作により、Linq、式ツリー、Type.MakeGenericType()、言語の独立性、コードの再利用などが可能になります。

ただし、代償があります。たとえば、ジェネリック型引数の値に演算子を使用することはできません。 C#でstd :: complexクラスを作成することはできません。また、コンパイル時のメタプログラミングはありません。

5
Hans Passant

いいえ、C#ではメタプログラミングはできません。

5
Brian

very限られた範囲で、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
}
3
JaredPar

それは可能になるでしょう。 Anders Hejlsberg The Future of C# トークをご覧ください。

3
Özgür

あなたが求めている方法ではありませんが、古い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> {}

この手法は、新しいデータメンバーを追加するには多くの定型文が必要な、多くのサブクラスがあるライブラリで使用します。

2
piojo