C#:「安全ではない」と明示的に指定する利点 / コンパイラ オプション

StackOverflow https://stackoverflow.com/questions/607159

質問

ポインターと、C# コードでポインターを使用する必要がまれにあることを理解しています。私の質問は次のとおりです。コードのブロックで「安全ではない」と明示的に記述する必要がある背後にある理由は何ですか。さらに、「安全でない」コードを許可するためにコンパイラ オプションを変更する必要があるのはなぜですか?

結論: CLR (または言語仕様) の何が原因で、「unsafe」と入力してコンパイラ オプションを変更することなく (C や C++ と同じように) いつでもポインタを使用することができますか?

明確にするために:「安全でない」コードと「安全な」コードが何であるかを知っています。これらの機能を使用できるようにするために、なぜ余分な作業 (それほど余分なことではありません) をしなければならないのかという疑問です。

役に立ちましたか?

解決

このテーマについて触れた、C# 作成者 Anders Hejlsberg へのインタビューがあります。 ここ. 。基本的に、@Marc Gravell が言ったこととまったく同じです。型安全性を第一に、明示的な宣言による非安全性。

したがって、あなたの質問に答えるには:CLR にはそれを妨げるものは何もありません。これは、型を扱うときに安全手袋を着用して作業できるように設計された言語イディオムです。手袋を外したい場合はあなたの選択ですが、手袋を外すという積極的な選択をしなければなりません。

編集:

明確にするために:「安全でない」コードと「安全な」コードが何であるかを知っています。これらの機能を使用できるように、なぜすべての追加作業を行う必要があるのか​​(OK、それほど余分ではない)という問題です。

リンクしたインタビューで述べたように、これは明確な設計上の決定でした。C# は本質的に Java の進化版であり、Java にはポインターがまったくありません。しかし、設計者はポインターを許可したいと考えました。ただし、C# は通常 Java 開発者を連れてくるため、C# は Java 開発者を採用するのが最善であると考えました。 デフォルト 動作は Java に似ています。つまり、ポインターはありませんが、明示的な宣言によるポインターの使用は引き続き許可されます。

つまり、「余分な作業」は、実行する前に自分が何をしているのか考えさせるために意図的に行われているのです。明示的にすることで、少なくとも次のことを考慮する必要があります。「なぜ私はこれをしているのですか?やりますか 本当に 参照型で十分なのにポインタが必要ですか?」

他のヒント

それは主に検証可能であることが重要です。と述べることで unsafe, 、手袋は外れています - システムはコードが暴走しないことを保証できなくなります。ほとんどの場合、安全ゾーンに留まることが非常に望ましいです。

これは部分信頼 (アドインなど) でより顕著になりますが、通常のコードでも依然として価値があります。

実際、CLR は /unsafe スイッチやキーワードについてまったく要件を設けません。実際、C++/CLI (CLR で実行される C++ 言語) にはそのような /unsafe スイッチがなく、CLR 上でポインターを自由に使用できます。

それで、私はあなたの質問を「なぜC#がポインターを使用する前に /安全を必要とするのか」と言います。そして、その質問に対する答えは、ここに与えられた他の答えに記載されているとおりです。これは、ユーザーが CLR 上で完全信頼モード以外で実行できないようにするという意識的な決定を下すのに役立ちます。C++ では事実上常に CLR および C# に対する完全な信頼が必要です できる 完全な信頼を必要とするコードを呼び出すとき、またはポインターを使用するとき。

安全でないブロックを使用すると、コードが検証不能になる影響があります。これを実行するには特定のアクセス許可が必要ですが、出力で許可したくない場合もあります (特に共有ソース環境にいる場合)。そのため、コンパイラには許可を禁止するスイッチがあります。

逆の観点から考えてみてください。安全ではないとマークされていないため、ほとんどのコードはデフォルトで「安全」であると推測できます。では、「安全」とは何を意味するのでしょうか?.Net コードの場合、これには以下が含まれます (ただし、これらに限定されない場合があります)。

  • ガベージ コレクターは通常どおり業務を行うことができます。
  • 特定の型への参照 意思 そのタイプ (または null) のオブジェクトを参照します。
  • コードは .Net の信頼/セキュリティ要件に準拠することが保証されています。
  • このコードは、独自の AppDomain の外部のメモリに直接触れないことが数学的に証明されています。些細なことのように思えるかもしれませんが、同じアプリケーション内に複数の AppDomain がある場合を想像してください。プログラマは、自信を持ってそれらを論理的に分離したものとして扱うことができます。

ポインターを使用するときはいつでも、これらの保証を破る可能性があります。したがって、コードを安全でないとしてマークすると、これらの保護が放棄されます。

つまり、.NET はユーザーに意図を述べてほしいと考えています。

確かに、コンパイラは「安全でない」フラグの必要性を推測することができます。しかし、デザイナーたちはそれが慎重な決定であることを望んでいます。

私にとって、これは C# のいくつかの構文要件に似ています。

  • スイッチケースなし、ブレークなし
  • アクセスレベルの「セクション」(C++ の「public:」マーカーなど)はありません。
  • 「var」を使用するクラスフィールドはありません

あるものを移動したり変更したりして、うっかり他のものに影響を与えてはいけないというパターンです。当然のことながら、彼らはあなたが「自分の足を撃つ」ことを避けたいと考えています。

ここには素晴らしい有益な回答がたくさんあります。おそらく、これがあなたの質問に当てはまります。

そのため、昇格されたアクセス許可などがなければ、どのコードが Web サービスで実行できないかがすぐにわかります。

良い習慣と安全を育みます。アセンブリ内で安全でないブロックを使用するときは常に、スタックから NativeCode アクセス許可が要求されます。もちろんこれは暗黙的に行うこともできますが、private キーワードを完全に削除することもできないでしょうか?開発者が安全でないコードを使用する前に、そのコードを明確に要求することを強制するのは良いことだと思います。

安全なコードと安全でないコードの最も重要な違いは、安全でないコードは .net のガベージ コレクターによって到達できないことです。自動 GC は .net の言語の大きな部分を占めており、その境界を越えると、コードに関して想定される多くのことが変更されます。

特にポインターを使用すると、GC 参照を使用せずにヒープ上にオブジェクトを作成できます。これは、コードを「安全でない」とマークすることを要求する別の優れた理由につながります。メモリリークがあることに気付いたときに、メモリリークがどこにあるかを絞り込むことができます。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top