web-dev-qa-db-ja.com

C#にマクロがないのはなぜですか?

C#を初めて学習したとき、C/C++に存在するのと同じ容量のマクロをサポートしていないことに驚いた。 #defineキーワードがC#に存在することを理解していますが、C/C++で好きになったものと比較すると、キーワードが大幅に不足しています。 realマクロがC#から欠落している理由を誰かが知っていますか?

この質問が何らかの形ですでに尋ねられた場合はお詫び申し上げます-投稿する前に重複を探すために確実な5分間を費やしたと約束します。

48
Andrew Garrison

c#FAQから。

http://blogs.msdn.com/CSharpFAQ/archive/2004/03/09/86979.aspx

C#が#defineマクロをサポートしないのはなぜですか? C++では、次のようなマクロを定義できます。

#define PRODUCT(x, y, z) x * y * z

そしてそれをコードで使用します:

int a = PRODUCT(3, 2, 1);

C#では、これを行うことはできません。どうして?

理由はいくつかあります。最初は読みやすさの1つです。

C#の主な設計目標の1つは、コードを非常に読みやすくすることです。マクロを作成する機能があると、プログラマーは独自の言語を作成することができます。その言語は、その下にあるコードとは必ずしも関係しません。コードの機能を理解するには、ユーザーは言語がどのように機能するかを理解するだけでなく、その時点で有効なすべての#defineマクロも理解する必要があります。これにより、コードが読みにくくなります。

C#では、マクロの代わりにメソッドを使用できます。ほとんどの場合、JITはそれらをインライン化し、同じパフォーマンスの側面を提供します。

もう少し微妙な問題もあります。マクロはテキストで行われます。つまり、次のように記述した場合、

int y = PRODUCT (1 + 2, 3 + 4, 5 + 6)

私は3 * 7 *11 = 231、しかし実際には、私が定義した拡張は次のようになります。

int y = 1 + 2 * 3 + 4 * 5 + 6;

これは私に33を与えます。括弧の賢明な適用によってそれを回避することができますが、状況によっては機能し、状況によっては機能しないマクロを書くのは非常に簡単です。

C#には厳密に言えばプリプロセッサはありませんが、コンパイルに影響を与えるために使用できる条件付きコンパイルシンボルがあります。これらは、コード内で定義することも、コンパイラへのパラメータを使用して定義することもできます。 C#の「前処理」ディレクティブ(個別の前処理ステップがないにもかかわらず、C/C++との一貫性のためだけに名前が付けられています)は(ECMA仕様からのテキスト):

#define and #undef条件付きコンパイルシンボルの定義と未定義に使用されます

#if, #Elif, #else and #endif

ソースコードのセクションを条件付きでスキップするために使用されます

#lineエラーおよび警告に対して発行される行番号を制御するために使用されます。

#error and #warningエラーと警告を発行するために使用されます。

#region and #endregion

ソースコードのセクションを明示的にマークするために使用されます。

上記の詳細については、ECMA仕様のセクション9.5を参照してください。メソッドのConditional属性を使用して条件付きコンパイルを実行することもできるため、メソッドの呼び出しは、適切なシンボルが定義されている場合にのみコンパイルされます。詳細については、ECMA仕様のセクション24.4.2を参照してください。

著者:エリックガンナーソン

67
DouglasH

これで、これを何度も何度も何度でも楽しく入力できます。

// Windows presetation foundation dependency property.
public class MyStateControl : ButtonBase
{
  public MyStateControl() : base() { }
  public Boolean State
  {
    get { return (Boolean)this.GetValue(StateProperty); }
    set { this.SetValue(StateProperty, value); } 
  }
  public static readonly DependencyProperty StateProperty = DependencyProperty.Register(
    "State", typeof(Boolean), typeof(MyStateControl),new PropertyMetadata(false));
}

明らかに、C#および.NETの設計者は、作成したライブラリやフレームワークを実際に使用することはありません。もしそうなら、彼らはある種のハイジェニック構文マクロシステムが間違いなく秩序であることを理解するでしょう。

CおよびC++の不完全なマクロの欠点が、コンパイル時に解決されるコードの力を弱体化させないようにしてください。コンパイル時間の解決とコード生成により、ソースコードの細かい細部をすべて詳しく説明する必要なく、コードの意味と意図をより効果的に表現できます。たとえば、上記を次のように置き換えるとどうなるでしょうか。

public class MyStateControl : ButtonBase
{
  public MyStateControl() : base() { }

  [DependencyProperty(DefaultValue=true)] 
  bool State { get; set; }
}

Booにはそれらがあり、OcamML(少なくともMeta ML)にはそれらがあり、CとC++にはそれらがあります(厄介な形式ですが、まったくないよりはましです)。 C#はサポートしていません。

35
bencooley

私の経験では、C++スタイルのマクロは、対応する利点なしに膨大な量の複雑さを追加します。 C#でもJavaでも確かに見逃していません。 (C#ではプリプロセッサシンボルを使用することはめったにありませんが、そこにあることをときどき嬉しく思います。)

現在、さまざまな人々が LISPスタイルのマクロ を求めています。これについてはほとんど知りませんが、C++スタイルのマクロよりもかなり快適に聞こえます。

マクロで特に何をしたいですか?私たちはあなたがより慣用的にC#の方法で考えるのを助けることができるかもしれません...

28
Jon Skeet

C#は、C++、C、またはASMより幅広いユーザー(または別の言い方をすると、消費者ベース)を対象としています。この目標を達成する唯一の方法は、かなり熟練していないプログラマに到達することです。したがって、すべての強力で危険なツールが取り除かれます。つまりマクロ、多重継承、オブジェクトの存続期間の制御、または型にとらわれないプログラミング。

マッチと同じように、ナイフとネイルガンは便利で必要ですが、子供の手の届かない場所に保管する必要があります。 (悲しいことに、放火、殺人、メモリリーク、読み取り不可能なコードが依然として発生します)。

そして、C#を考えていないと非難する前に、何回書いたのですか。

protected int _PropOne;
public int PropOne
{
    get
    {
        return _PropOne;
    }
    set
    {
        if(value == _PropOne) { return; }
        NotifyPropertyChanging("PropOne");
        _PropOne = value;
        NotifyPropertyChanged("PropOne");
    }
}

マクロを使用すると、これらの16行は次のようになります。

DECLARE_PROPERTY(int, PropOne)
DECLARE_PROPERTY(string, PropTwo)
DECLARE_PROPERTY(BitmapImage, PropThree)
9
Agent_L

C/C++のマクロは、定数の定義、小さなインライン関数の生成、およびコードのコンパイルに直接関連するさまざまな処理(#ifdef)に使用されました。

C#では、強く型付けされた定数があり、必要に応じて関数をインライン化するのに十分スマートで、適切にコンパイルする方法を知っています(プリコンパイル済みヘッダーが意味をなさない)。

しかし、本当にしたいのであれば、最初にCプリプロセッサでCSファイルを実行できなかった特別な理由はありません:)

4
Seth

しばらくC++を学び始めた長年のC#プログラマーとして、メタプログラミングC#の豊富なサポートを失いました。少なくとも、メタプログラミングが何を意味するのかについて、私はより広範な感謝の意を表しています。

C#の Nemerle に組み込まれている種類のマクロサポートが本当に必要です。言語に非常に自然で強力な拡張機能を追加するようです。まだご覧になっていない場合は、ぜひご覧になることをお勧めします。

Wikipedia にはいくつかの素晴らしい例があります。

2
Drew Noakes

マクロはC++ですが、それらには それらの使用 がまだありますが、これらの使用のほとんどはC#リフレクションとエラー報告のための例外のより統合された使用のため。

1
Motti

この記事ではPerlマクロとLISPマクロを比較しますが、要点は同じです。テキストレベルマクロ(Perl/c ++)は、ソースレベルマクロ(LISP)に比べて大きな問題を引き起こします。

http://lists.warhead.org.uk/pipermail/iwe/2005-July/000130.html

私よりも勇敢な人々がc#でシステムのような独自のマクロを展開しています http://www.codeproject.com/KB/recipes/prepro.aspx

1
Matthew Lock

マクロが悪いという考えに同意する人は、「With Folded Hands」という本を読んでください。 http://en.wikipedia.org/wiki/With_Folded_Hands 人々が愚かなことをしないようにして、非常に賢明なことをするのを防ぐことができるという話を伝えます。

私はC#が好きですが、実際のソフトウェアエンジニアの愚かさの原因となることは本当に嫌いです。だから、はい、マクロは専門家に任せてください。変数の命名も専門家に任せます。それはいくつかの本当に読みにくいコードを作ることができます。 「コードは最終的に読み取り可能である必要がある」という完全なステートメントに従うには、すべての変数にA-Zという名前を付け、その後にa-z(または名詞のみのような他の任意の構文)を付ける必要があります。一部の非熟練者は、変数に「SomethingUsefulButNotAllowedByTheCompilerBecauseSomeUsersMayDoDumbThings」という名前を付ける場合があるためです。

0
Kevin Williams

マクロは、ほとんどのプログラマーがコンパイラーより賢い時代のツールです。 C/C++では、これが当てはまる場合がまだいくつかあります。

今日、ほとんどのプログラマーはC#コンパイラー/ランタイムほどスマートではありません。

0
Imagist