Определения макросов C # в препроцессоре - PullRequest
59 голосов
/ 02 апреля 2009

Может ли C # определять макросы, как это делается в языке программирования C с помощью операторов препроцессора? Я хотел бы упростить регулярную типизацию некоторых повторяющихся утверждений, таких как:

Console.WriteLine("foo");

Ответы [ 9 ]

45 голосов
/ 02 апреля 2009

Нет, C # не поддерживает макросы препроцессора, такие как C. С другой стороны, Visual Studio имеет фрагменты . Фрагменты Visual Studio являются функцией среды IDE и расширяются в редакторе, а не заменяются в коде при компиляции препроцессором.

33 голосов
/ 29 марта 2013

Вы можете использовать препроцессор C (например, mcpp) и вставить его в файл .csproj. Затем вы изменяете «действие сборки» в вашем исходном файле из Compile в Preprocess или как вы его называете. Просто добавьте BeforBuild к вашему .csproj так:

  <Target Name="BeforeBuild" Inputs="@(Preprocess)" Outputs="@(Preprocess->'%(Filename)_P.cs')">
<Exec Command="..\Bin\cpp.exe @(Preprocess) -P -o %(RelativeDir)%(Filename)_P.cs" />
<CreateItem Include="@(Preprocess->'%(RelativeDir)%(Filename)_P.cs')">
  <Output TaskParameter="Include" ItemName="Compile" />
</CreateItem>

Возможно, вам придется вручную изменить Compile на Preprocess хотя бы для одного файла (в текстовом редакторе) - тогда опция «Preprocess» будет доступна для выбора в Visual Studio.

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

27 голосов
/ 07 сентября 2012

Я использую это, чтобы избежать Console.WriteLine(...):

public static void Cout(this string str, params object[] args) { 
    Console.WriteLine(str, args);
}

и затем вы можете использовать следующее:

"line 1".Cout();
"This {0} is an {1}".Cout("sentence", "example");

это сжато и отчасти фанки.

10 голосов
/ 08 ноября 2015

Хотя вы не можете писать макросы, когда речь идет об упрощении таких вещей, как ваш пример, C # 6.0 теперь предлагает статическое использование. Вот пример, который Мартин Перника привел в своей средней статье :

using static System.Console; // Note the static keyword

namespace CoolCSharp6Features
{
  public class Program
  {
    public static int Main(string[] args)
    {
      WriteLine("Hellow World without Console class name prefix!");

      return 0;
    }
  }
}
4 голосов
/ 13 мая 2015

Не существует прямого эквивалента макросов в стиле C в C #, но inline d статические методы - с или без #if / #elseif / #else прагмы - самые близкие, которые можно получить:

        /// <summary>
        /// Prints a message when in debug mode
        /// </summary>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe void Log(object message) {
#if DEBUG
            Console.WriteLine(message);
#endif
        }

        /// <summary>
        /// Prints a formatted message when in debug mode
        /// </summary>
        /// <param name="format">A composite format string</param>
        /// <param name="args">An array of objects to write using format</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe void Log(string format, params object[] args) {
#if DEBUG
            Console.WriteLine(format, args);
#endif
        }

        /// <summary>
        /// Computes the square of a number
        /// </summary>
        /// <param name="x">The value</param>
        /// <returns>x * x</returns>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static double Square(double x) {
            return x * x;
        }

        /// <summary>
        /// Wipes a region of memory
        /// </summary>
        /// <param name="buffer">The buffer</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe void ClearBuffer(ref byte[] buffer) {
            ClearBuffer(ref buffer, 0, buffer.Length);
        }

        /// <summary>
        /// Wipes a region of memory
        /// </summary>
        /// <param name="buffer">The buffer</param>
        /// <param name="offset">Start index</param>
        /// <param name="length">Number of bytes to clear</param>
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static unsafe void ClearBuffer(ref byte[] buffer, int offset, int length) {
            fixed(byte* ptrBuffer = &buffer[offset]) {
                for(int i = 0; i < length; ++i) {
                    *(ptrBuffer + i) = 0;
                }
            }
        }

Это прекрасно работает как макрос, но имеет небольшой недостаток: методы, отмеченные как inline d, будут скопированы в отражающую часть вашей сборки, как и любой другой «нормальный» метод.

2 голосов
/ 02 апреля 2009

К счастью, в C # нет препроцессора в стиле C / C ++ - поддерживаются только условная компиляция и прагмы (и, возможно, что-то еще, что я не могу вспомнить). К сожалению, C # не имеет возможности метапрограммирования (это может на самом деле относится к вашему вопросу в некоторой степени).

1 голос
/ 07 февраля 2011

Я бы предложил вам написать расширение, что-то вроде ниже.

public static class WriteToConsoleExtension
{
   // Extension to all types
   public static void WriteToConsole(this object instance, 
                                     string format, 
                                     params object[] data)
   {
       Console.WriteLine(format, data);
   }
}

class Program
{
    static void Main(string[] args)
    {
        Program p = new Program();
        // Usage of extension
        p.WriteToConsole("Test {0}, {1}", DateTime.Now, 1);
    }
}

Надеюсь, это поможет (и не слишком поздно :))

1 голос
/ 02 апреля 2009

Преврати макрос C в статический метод C # в классе.

0 голосов
/ 17 августа 2018

Поскольку C # 7.0 поддерживает директиву using static и Локальные функции , в большинстве случаев вам не нужны макросы препроцессора.

...