Возможно ли метапрограммирование на 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
}

Хотя это невозможно в C#, это возможно в альтернативных строго типизированных языках .NET, таких как Бу и Nemerle.

Jordão 26.10.2010 17:15

Вы можете прочитать «Метапрограммирование в .NET manning.com/hazzard» Кевина Хаззарда и Джейсона Бока.

Matija Grcic 15.10.2013 12:20

@ Jordão: Boo - совсем другой язык, а Nemerle более или менее мертв, так как Jetbrains наняли мозги. Возможно, стоит упомянуть Script.NET.

david.pfx 01.07.2016 03:49

попробуйте взглянуть на script.net; больше информации на --orbifold.net/default/?p=2457

user309010 07.04.2010 09:43

как бы искать шаблоны t4 Извините на iphone, но не могу указать на ресурс. Скотт Ханслеман написал об этом на прошлой неделе.

littlegeek 26.10.2008 09:01
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
39
5
26 673
9
Перейти к ответу Данный вопрос помечен как решенный

Ответы 9

Нет, в 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
}

Спрашивающий на самом деле не уточнил, что они подразумевают под метапрограммированием, но я думаю, что можно с уверенностью сказать, что это отличается от того, что вы имеете в виду.

Anthony 03.01.2009 20:12

@Anthony, проблема с неоднозначными вопросами в том, что они дают неверные или непреднамеренные ответы. Я не мог ответить на вопрос или дать ответ, который может отвечать на вопрос. Пока я здесь, я думаю, что могу ответить :)

JaredPar 03.01.2009 21:57
Ответ принят как подходящий

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

нет проблем, маленький гик; Я проголосовал за то, что ты обыграл меня на 4 часа даже без буфера обмена :)

Jacob Krall 26.10.2008 09:20

Ссылка "Text Template Transformation Toolkit" не работает, попробуйте вместо этого: wekeroad.com/2008/10/13/…

Grant Peters 16.01.2012 11:26

@GrantPeters, даже этот сейчас сломан

Stan Prokop 23.02.2014 00:55

@StanislavProkop Я удалил неработающую ссылку и поднял статью Скотта Хансельмана на главную.

Jacob Krall 24.02.2014 01:32

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

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

Я по опыту знаю, что код шаблона можно использовать повторно. И так называемая «языковая независимость», о которой вы говорите, на самом деле означает, что вы должны использовать язык, совместимый с .net ... Существуют ограничения как для обобщенных шаблонов .net, так и для шаблонов C++. Но это не те.

Benoît 09.02.2009 14:23

И, конечно же, вы МОЖЕТЕ написать класс комплексных чисел (или, еще лучше, структуру) на C#, но библиотеки шаблонов, которые выполняют вычисления с параметрами числового типа, трудно написать и использовать, см. codeproject.com/KB/cs/genericnumerics.aspx и codeproject.com/KB/cross-platform/BenchmarkCppVsDotNet.aspx

Qwertie 18.10.2011 21:18

«Вы не можете написать класс std :: complex на C#». В каком смысле?

J D 22.02.2012 14:36

@JonHarrop В том смысле, что производительность будет отстой, и вы потеряете безопасность времени компиляции. А некоторые части, связанные с преобразованием, вообще невозможны.

CodesInChaos 22.02.2012 14:49

@CodeInChaos: почему вы считаете, что производительность будет отстой, какую безопасность во время компиляции вы теряете и какие части преобразования вообще невозможны?

J D 23.02.2012 13:18

1) Нет общих ограничений для перегруженных операторов. Таким образом, вы теряете безопасность во время компиляции. 2) Без этих ограничений ни один пользовательский оператор не может быть выбран по специализации. Таким образом, вам нужно использовать генерацию методов времени выполнения, и вы получаете накладные расходы на вызов делегата всякий раз, когда вы вызываете оператор. 3) Вы не можете выразить что-то вроде «если T1 неявно конвертируется в T2, то Complex<T1> должен быть неявно конвертируемым в Complex<T2>».

CodesInChaos 23.02.2012 15:17

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

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

Ваш комментарий был написан в 2009 году. Десять лет спустя это все еще невозможно.

Dmitri Nesteruk 07.10.2019 23:50

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

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

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

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

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

-1: Хороший ответ, но он не отвечает на этот конкретный вопрос.

John Saunders 26.02.2010 21:57

@Saunders: На самом деле это так, но вам нужно сделать домашнее задание. Если вы хотите реализовать конкретную задачу OP, вам необходимо реализовать преобразования программы с постоянным сворачиванием и сосредоточить их на вызовах вашей функции Фибоначчи. Я отмечаю, что вы изменили мой ответ, когда ни один из ответов также не касался конкретного вопроса OP.

Ira Baxter 26.02.2010 22:00

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

Ralph Willgoss 18.06.2010 09:05

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

+1 за краткий и исчерпывающий ответ на все аспекты вопроса.

Marc Sigrist 26.02.2012 15:57

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

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

Другие вопросы по теме