C#は、プリプロセッサステートメントを使用してCプログラミング言語で行われているようにマクロを定義できますか?次のような特定の繰り返しステートメントの定期的な入力を簡単にしたいと思います。
Console.WriteLine("foo");
いいえ、C#はCなどのプリプロセッサマクロをサポートしていません。一方、Visual Studioには snippets があります。 Visual StudioのスニペットはIDEの機能であり、プリプロセッサによるコンパイル時にコードで置き換えられるのではなく、エディタで展開されます。
Cプリプロセッサ(mcppなど)を使用して、.csprojファイルにリグできます。次に、ソースファイルの「ビルドアクション」をコンパイルからプリプロセスまたはそれを呼び出すものに変更します。次のように、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>
少なくとも1つのファイルでコンパイルを前処理に手動で変更しなければならない場合があります(テキストエディターで)-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");
簡潔でファンキーです。
マクロを書くことはできませんが、例のようなものを単純化することになると、C#6.0は静的な使用を提供します。以下は、Martin Pernicaが 彼の中記事 で与えた例です。
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
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としてマークされたメソッドは、他の「通常の」メソッドと同様にアセンブリのリフレクション部分にコピーされます。
幸いなことに、C#にはC/C++スタイルのプリプロセッサがありません。条件付きコンパイルとプラグマ(および場合によっては思い出せない何か)のみがサポートされています。残念ながら、C#にはメタプログラミング機能がありません(これはmay実際に質問にある程度関連しています)。
以下のような拡張機能を作成することをお勧めします。
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マクロをクラス内のC#静的メソッドに変換します。
C#7.0はusing static
ディレクティブと ローカル関数 ほとんどの場合、プリプロセッサマクロは必要ありません。