Kann C # Makros wie in der Programmiersprache C mit Pre-Prozessor-Anweisungen definieren? Ich möchte die regelmäßige Eingabe bestimmter sich wiederholender Anweisungen wie der folgenden vereinfachen:
Console.WriteLine("foo");
Kann C # Makros wie in der Programmiersprache C mit Pre-Prozessor-Anweisungen definieren? Ich möchte die regelmäßige Eingabe bestimmter sich wiederholender Anweisungen wie der folgenden vereinfachen:
Console.WriteLine("foo");
Antworten:
Nein, C # unterstützt keine Präprozessor-Makros wie C. Visual Studio verfügt dagegen über Snippets . Die Ausschnitte von Visual Studio sind eine Funktion der IDE und werden im Editor erweitert, anstatt beim Kompilieren durch einen Präprozessor im Code ersetzt zu werden.
#if/#elseif/#else
bei einigen einfachen Makros viel Code zwischen Pragmas einfügen müssen man könnte den richtigen Code für jedes Ziel auf effiziente / elegante und wartbare Weise ausgeben. Kurz gesagt, Makros im C-Stil sind sehr hilfreich, wenn Sie Code einfügen müssen, der auf einigen Zielen einfach nicht kompiliert werden kann.
#ifdefs
umliegender großer Codeblöcke gut ist. Es ist nicht. Ich sage, dass die gerichtliche Verwendung von #define MACRO(x,y)
eingebettet in #ifdef PLATFORM1 #elif PLATFORM2 ...
in begrenzten Fällen als Werkzeug in der Toolbox nützlich sein kann. Vielleicht sind Sie auch damit nicht einverstanden - nach einer Google-Suche zur Verteidigung des Präprozessors scheint dies auch für den größten Teil der Welt der Fall zu sein. Aber ich bin auf dieses Juwel gestoßen.
Sie können einen C-Präprozessor (wie mcpp) verwenden und ihn in Ihre .csproj-Datei einbinden. Dann ändern Sie "Build Action" für Ihre Quelldatei von Compile to Preprocess oder wie auch immer Sie es nennen. Fügen Sie einfach BeforBuild zu Ihrem CSPROJ wie folgt aus :
<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>
Möglicherweise müssen Sie die Kompilierung für mindestens eine Datei (in einem Texteditor) manuell in Vorverarbeitung ändern. Dann sollte die Option "Vorverarbeitung" in Visual Studio zur Auswahl verfügbar sein.
Ich weiß, dass Makros stark überbeansprucht und missbraucht werden, aber das vollständige Entfernen ist genauso schlecht, wenn nicht schlimmer. Ein klassisches Beispiel für die Verwendung von Makros wäre NotifyPropertyChanged . Jeder Programmierer, der diesen Code tausende Male von Hand umschreiben musste, weiß, wie schmerzhaft er ohne Makros ist.
MyCommon.targets
einfach falsch sein ? Es gibt nur einige Dinge, die CPP tun kann, die die Sprache unglaublich schwierig macht. IMO, es ist schlimmer, dass der Entwickler beim Schreiben einen Argumentnamen tatsächlich manuell stringifizieren muss throw new ArgumentNullException("argumentName");
. Code-Verträge sollten das lösen, aber es erfordert einen IL-Umschreiber, der angeschraubt .targets
ist. Es sollte nicht schlimmer sein, einen CPP-Aufruf anzulegen .
nameof(argumentX)
. C # 6 und 7 fügten viele tiefgreifende und direkte Lösungen für triviale Probleme hinzu, die früher Schmerzen verursachten, wie dieses. Und ich muss @danpalmer ehrlich zustimmen - ja, je mehr Hacks wie diese hinzugefügt werden, desto unwahrscheinlicher ist es, dass jemand ein Projekt pflegen oder sogar einige Jahre später kompilieren möchte.
Ich benutze dies, um Folgendes zu vermeiden Console.WriteLine(...)
:
public static void Cout(this string str, params object[] args) {
Console.WriteLine(str, args);
}
und dann können Sie Folgendes verwenden:
"line 1".Cout();
"This {0} is an {1}".Cout("sentence", "example");
Es ist prägnant und irgendwie funky.
Console.WriteLine(...)
(was ziemlich lang ist, um häufig tippen zu müssen). Sie könnten Ihre eigene Methode schreiben, um dies zu tun, aber die Verwendung einer String-Erweiterung ist meiner Meinung nach etwas eleganter.
Während Sie keine Makros schreiben können, bietet C # 6.0 jetzt statische Verwendungen, wenn es darum geht, Dinge wie Ihr Beispiel zu vereinfachen. Hier ist das Beispiel, das Martin Pernica in seinem Medium-Artikel gegeben hat :
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;
}
}
}
Es gibt kein direktes Äquivalent zu Makros im C-Stil in C #, aber inline
d statische Methoden - mit oder ohne #if
/ #elseif
/ #else
Pragmas - sind die nächsten, die Sie erhalten können:
/// <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;
}
}
}
Dies funktioniert perfekt als Makro, hat jedoch einen kleinen Nachteil: Mit inline
d gekennzeichnete Methoden werden wie jede andere "normale" Methode in den Reflexionsteil Ihrer Baugruppe kopiert.
[ConditionalAttribute("DEBUG")]
diesen Methoden den gleichen Effekt wie mit dem #if
s erzielen ?
Glücklicherweise hat C # keinen Präprozessor im C / C ++ - Stil - nur bedingte Kompilierung und Pragmas (und möglicherweise etwas anderes, an das ich mich nicht erinnern kann) werden unterstützt. Leider verfügt C # über keine Metaprogrammierfunktionen (dies kann in gewissem Maße tatsächlich mit Ihrer Frage zusammenhängen).
quit
Variablen überlegen ist. Sobald verschachtelte Anweisungen vorhanden sind, ist Code schwer zu lesen und zu warten. PHP hat die break 2..n;
Anweisung, C # nicht. C # verfügt jedoch über genügend LINQ-Erweiterungen, um in vielen Fällen keine verschachtelten Schleifen zu verwenden, sodass der Code auf andere Weise lesbar ist - was ich ehrlich bevorzuge.
Verwandeln Sie das C-Makro in eine statische C # -Methode in einer Klasse.
Ich würde Ihnen vorschlagen, eine Erweiterung zu schreiben, so etwas wie unten.
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);
}
}
Hoffe das hilft (und nicht zu spät :))
ValidateUrl(this string)
- Etwas, das ich mittlerweile in einer Klasse bevorzuge, da dies dazu neigt, Intellisense (besonders bei this object
) aufzublähen und es manchmal dunkel macht, solche Methoden zu finden. Nachdem Sie Validate.Url(string)
den Code nicht sprengen und ist offenbar leicht für andere zu finden und zu nutzen.
Da C # 7.0 using static
Direktiven- und lokale Funktionen unterstützt, benötigen Sie in den meisten Fällen keine Präprozessormakros.
Ich werde einen C # -Makrocompiler namens C # -Makros erstellen.
Fortschritt ist hier .
cw
in Visual Studio schreiben und die Tabulatortaste drücken.