Возможно ли метапрограммирование в C #? - PullRequest
35 голосов
/ 26 октября 2008

В частности, возможно ли иметь код , похожий на этот код 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
}

Ответы [ 9 ]

31 голосов
/ 26 октября 2008

Нет, метапрограммирование этой сложности напрямую не поддерживается языком C #. Однако, как сказал @ littlegeek , Инструмент преобразования текстовых шаблонов , входящий в состав Visual Studio, позволит вам создать код любой сложности.

24 голосов
/ 22 февраля 2012

Метапрограммирование возможно в .NET (см. Компиляторы, регулярные выражения, код DOM, отражение и т. Д.), Но C # не способен к шаблону метапрограммированию, поскольку у него нет этой языковой функции.

6 голосов
/ 26 февраля 2010

Большинство людей настаивают на попытке метапрограммирования изнутри их любимого языка. Это не работает, если язык не поддерживает метапрограммирование; другие ответы отметили, что C # не делает.

Обойти это можно, выполнив метапрограммирование из вне языка, используя инструменты преобразования программ . Такие инструменты могут анализировать исходный код и выполнять произвольные преобразования над ним (в любом случае это делает метапрограммирование), а затем выплевывать пересмотренную программу.

Если у вас есть система преобразования программ общего назначения, которая может анализировать произвольные языки, вы можете затем выполнять метапрограммирование на / на любом языке, который вам нравится. Смотрите наш DMS Software Reengineering Toolkit для такого инструмента, который имеет надежные внешние интерфейсы для C, C ++, Java, C #, COBOL, PHP и ряда других языков программирования и использовался для метапрограммирования на всех из этих.

DMS преуспевает, потому что обеспечивает регулярный метод и инфраструктуру поддержки для полного доступа к структуре программы в виде AST, и в большинстве случаев дополнительные данные, такие как таблицы символов, информация о типе, контроль и анализ потока данных, все необходимое для выполнения сложной программы манипуляция.

РЕДАКТИРОВАТЬ (в ответ на комментарий): Можно применить DMS для реализации задачи OP на C #.

6 голосов
/ 11 ноября 2008

Вы должны быть осторожны, когда говорите о времени компиляции при работе с языками Java или .Net. В этих языках вы можете выполнять более мощную метапрограммирование (в более широком смысле - рефлексия), чем в C ++, потому что «время компиляции» (JIT) может быть отложено после «времени выполнения»;)

5 голосов
/ 26 октября 2008

Нет, метапрограммирование невозможно в C #.

4 голосов
/ 03 января 2009

Это будет возможно. Смотреть Будущее C # Андерса Хейлсберга.

4 голосов
/ 26 октября 2008

Существенное различие между шаблонами .NET Generics и C ++ состоит в том, что дженерики специализируются во время выполнения. Шаблоны раскрываются во время компиляции. Динамическое поведение обобщенных элементов делает возможными такие вещи, как Linq, деревья выражений, Type.MakeGenericType (), независимость от языка и возможность повторного использования кода.

Но есть цена, вы не можете, например, использовать операторы для значений аргумента универсального типа. Вы не можете написать класс std :: complex в C #. И нет метапрограммирования во время компиляции.

3 голосов
/ 26 октября 2008

В очень ограниченной степени, 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
}
1 голос
/ 12 ноября 2013

Не так, как вы просите, но вы можете использовать некоторые старые приемы 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> {}

Я использую эту технику в библиотеке, которая имеет много подклассов, где добавление нового элемента данных требует большого количества шаблонов.

...