プロジェクトの1つには、次のような多くのコードがあります。
internal static class Extensions
{
public static string AddFoo(this string s)
{
if (!string.IsNullOrEmpty(s)) return s + "Foo";
return "Foo";
}
}
「後で型を公開する方が簡単です」以外にこれを行う明確な理由はありますか?
非常に奇妙なEdgeケース(Silverlightでのリフレクション)でのみ問題になるか、まったく問題ではないと思います。
更新:この質問は 2014年9月の私のブログの主題 でした。すばらしい質問をありがとう!
この質問については、コンパイラチーム内でもかなりの議論があります。
まず、ルールを理解するのが賢明です。クラスまたは構造体のパブリックメンバーは、を含む型にアクセスできるものであればアクセス可能なメンバーです。したがって、内部クラスのパブリックメンバーは事実上内部です。
それでは、内部クラスが与えられた場合、アセンブリでアクセスするメンバーをパブリックまたは内部としてマークする必要がありますか?
私の意見では、このようなメンバーを公開としてマークします。
「パブリック」とは、「このメンバーは実装の詳細ではない」という意味です。保護されたメンバーは実装の詳細です。派生クラスを機能させるために必要なものがあります。内部メンバーは実装の詳細です。このアセンブリの内部で何かが正しく機能するには、メンバーが必要です。パブリックメンバは、「このメンバは、このオブジェクトによって提供される文書化されたキー機能を表す」と言います。
基本的に、私の態度は次のとおりです。この内部クラスをパブリッククラスにすると決めたとします。それを行うために、1つだけ変更します:クラスのアクセシビリティ。内部クラスをパブリッククラスにすると、内部メンバーもパブリックメンバーに変更する必要がある場合、そのメンバーはpublic surface areaの一部でしたクラス、それはそもそも公開されるべきだった。
他の人は同意しません。メンバーの宣言を一目見、それが内部コードからのみ呼び出されるかどうかをすぐに知ることができるようにしたいということを条件としています。
残念ながら、それは常にうまくいくとは限りません。たとえば、内部インターフェイスを実装する内部クラスには、theyがクラスのパブリックサーフェスの一部であるため、実装メンバーをパブリックとしてマークする必要があります。
クラスがinternal
の場合、アクセシビリティの観点から、メソッドinternal
をマークするか、public
をマークするかは重要ではありません。ただし、クラスがpublic
である場合に使用する型を使用することをお勧めします。
これにより、internal
からpublic
への移行が容易になると言われています。また、メソッドの説明の一部として機能します。 Internal
メソッドは通常、制限のないアクセスに対して安全ではないと見なされますが、public
メソッドは(ほとんど)無料ゲームと見なされます。
internal
クラスで使用するようにpublic
またはpublic
を使用することにより、どのようなスタイルのアクセスが期待されているかを確実に伝えると同時に、将来的にクラスpublic
を作成するために必要な作業を軽減します。
私は頻繁に内部の代わりに内部クラスのメソッドをパブリックとしてマークしますa)それは本当に問題ではありませんb)内部を使用して、メソッドが意図的に内部であることを示す(これを公開したくない理由がありますパブリッククラスのメソッドです。したがって、内部メソッドがある場合は、パブリックに変更する前に内部の理由を本当に理解する必要がありますが、内部クラスでパブリックメソッドを扱う場合は、なぜ各メソッドが内部である理由とは対照的に、クラスは内部です。
「後で型を公開する方が簡単ですか?」それは...ですか。
スコープ規則は、メソッドがinternal
としてのみ表示されることを意味します。したがって、メソッドがpublic
またはinternal
とマークされているかどうかは実際には関係ありません。
思い浮かぶ可能性の1つは、クラスwas publicであり、後でinternal
に変更され、開発者がすべてのメソッドのアクセシビリティ修飾子を変更することを気にしなかったことです。
場合によっては、内部型がパブリックインターフェイスを実装している可能性もあります。これは、そのインターフェイスで定義されたメソッドはすべてパブリックとして宣言する必要があることを意味します。
それは同じです、パブリックメソッドは内部クラス内にあるため、実際には内部としてマークされますが、(ゲストとして)利点があります。クラスをパブリックとしてマークしたい場合は、より少ないコードを変更する必要があります。
internal
は、同じアセンブリ内からのみメンバーにアクセスできると言います。そのアセンブリの他のクラスはinternal public
メンバーにアクセスできますが、private
またはprotected
メンバー、internal
メンバーにはアクセスできません。
私は実際に今日これに苦労しました。これまでは、クラスがinternal
であった場合、メソッドはすべてinternal
でマークされ、特にエンタープライズ開発では、コーディングや遅延が単に悪いと見なされると言っていました。ただし、public
クラスをサブクラス化し、そのメソッドの1つをオーバーライドする必要がありました。
internal class SslStreamEx : System.Net.Security.SslStream
{
public override void Close()
{
try
{
// Send close_notify manually
}
finally
{
base.Close();
}
}
}
メソッドはpublic
である必要があり、Eric Lippertが言ったように、メソッドが本当に必要でなければinternal
としてメソッドを設定することは論理的に意味がないと考えるようになりました。
今までそれについて考えるのをやめたことは一度もありませんでしたが、エリックの投稿を読んだ後、本当に考えさせられ、多くの審議の後、それは非常に理にかなっています。
私はこれについて追加の意見があると思います。最初は、内部クラスで何かをpublicに宣言するのが理にかなっていると思っていました。その後、私はここで終わりました。後でクラスを公開に変更することを決めたらいいかもしれないと読んでいます。本当です。だから、パターンは私の心の中に形成された:それが現在の行動を変えないなら、寛容であり、物事を許可するコードの現在の状態ではそれは理にかなっていない(そして傷つけない)が、クラスの宣言を変更した場合は後でそうなる。
このような:
public sealed class MyCurrentlySealedClass
{
protected void MyCurretlyPrivateMethod()
{
}
}
上で述べた「パターン」によれば、これはまったく問題ないはずです。同じ考え方に従っています。クラスを継承できないため、private
メソッドとして動作します。しかし、sealed
制約を削除しても、それは有効です。継承されたクラスはこのメソッドを見ることができ、これは私が絶対に達成したかったものです。ただし、警告が表示されます:CS0628
、またはCA1047
。両方とも、protected
クラスでsealed
メンバーを宣言しないでください。さらに、私はそれが無意味であることについて完全な合意を見つけました: 「保護されたクラスの保護されたメンバー」警告(シングルトンクラス)
したがって、この警告と議論がリンクされた後、私は内部クラスですべてを内部またはそれ以下にすることにしました。なぜなら、それはそのような考え方に適合し、異なる「パターン」を混在させないからです。
違いがあります。このプロジェクトでは、多くのクラスを内部に作成しましたが、別のアセンブリでユニットテストを行い、アセンブリ情報でInternalsVisibleToを使用して、UnitTestアセンブリが内部クラスを呼び出せるようにしました。内部クラスに内部コンストラクターがある場合、何らかの理由で単体テストアセンブリのActivator.CreateInstanceを使用してインスタンスを作成できないことに気付きました。ただし、コンストラクターをpublicに変更しても、クラスが内部にある場合、正常に機能します。しかし、これは非常にまれなケースだと思います(エリックが元の投稿で述べたように:Reflection)。