Определения макросов C# в препроцессоре


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

Console.WriteLine("foo");
9 54

9 ответов:

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

вы можете использовать препроцессор C (например, mcpp) и установить его в свой .файл csproj. Затем вы chnage "build action" на исходном файле от компиляции до предварительной обработки или как вы его называете. Просто добавьте 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" должна быть доступна для выбора в Visual Studio.

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

Я использую это, чтобы избежать 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");

это лаконично и kindof фанки.

хотя вы не можете писать макросы, когда дело доходит до упрощения таких вещей, как ваш пример, 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;
    }
  }
}

в C# нет прямого эквивалента макросам C-стиля, но inlineд статические методы - С или без #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;
                }
            }
        }

это прекрасно работает как макрос, но имеет небольшой недостаток: методы помечены как inlined будет скопирован в отражающую часть вашей сборки, как и любой другой "нормальный" метод.

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

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

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

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);
    }
}

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

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