web-dev-qa-db-fra.com

Définitions de macro C # dans le préprocesseur

C # peut-il définir des macros comme dans le langage de programmation C avec des instructions de pré-processeur? J'aimerais simplifier la saisie régulière de certaines déclarations répétitives, telles que: 

Console.WriteLine("foo");
55
cl123

Non, C # ne prend pas en charge les macros de préprocesseur comme C. Visual Studio, par contre, contient snippets . Les extraits de Visual Studio sont une fonctionnalité de IDE et sont développés dans l'éditeur plutôt que remplacés dans le code lors de la compilation par un préprocesseur.

43
Andrew Hare

Vous pouvez utiliser un préprocesseur C (tel que mcpp) et l'intégrer dans votre fichier .csproj. Ensuite, vous devez "créer une action" sur votre fichier source depuis Compile to Preprocess ou peu importe comment vous l'appelez . Ajoutez simplement BeforBuild à votre .csproj comme ceci:

  <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>

Vous devrez peut-être modifier manuellement Compiler en prétraitement sur au moins un fichier (dans un éditeur de texte). L'option "Prétraitement" doit alors être disponible pour la sélection dans Visual Studio.

Je sais que les macros sont largement surutilisées et mal utilisées, mais les supprimer complètement est tout aussi grave sinon pire. Un exemple classique d'utilisation de macro serait NotifyPropertyChanged . Tous les programmeurs qui ont dû réécrire ce code à la main des milliers de fois savent à quel point il est douloureux sans macros.

31
user2224389

J'utilise ceci pour éviter Console.WriteLine(...):

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

et vous pouvez ensuite utiliser les éléments suivants:

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

c'est concis et un peu funky.

26
anthonybell

Bien que vous ne puissiez pas écrire de macros, lorsqu'il s'agit de simplifier des choses comme votre exemple, C # 6.0 offre désormais des utilisations statiques. Voici l'exemple de Martin Pernica sur son article de Medium :

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;
    }
  }
}
9
sraboy

Il n'y a pas d'équivalent direct aux macros de style C en C #, mais les méthodes inlined statiques - avec ou sans #if/#elseif/#else pragmas - sont les plus proches que vous pouvez obtenir:

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

Cela fonctionne parfaitement en tant que macro, mais présente un petit inconvénient: les méthodes marquées avec inlined seront copiées dans la partie réflexion de votre assemblage comme toute autre méthode "normale".

4
Binkan Salaryman

Heureusement, C # n'a pas de préprocesseur de style C/C++ - seuls la compilation conditionnelle et les pragmas (et éventuellement quelque chose d'autre que je ne me souviens pas) sont supportés. Malheureusement, C # n’a pas de capacité de métaprogrammation (ceci peut concerne réellement votre question dans une certaine mesure).

2
Anton Gogolev

Transformez la macro C en une méthode statique C # dans une classe.

2
Robert

Comme C # 7.0 prend en charge la directive using static et Fonctions locales vous n’avez pas besoin de macros de préprocesseur dans la plupart des cas. 

0
moien

Je vous suggère d'écrire une extension, quelque chose comme ci-dessous.

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

J'espère que ça aide (et pas trop tard :)) 

0
Milan Jaric