[c#] C#の "internal"キーワードの実用的な使用



10 Answers

BobがBigImportantClassを必要とする場合、Bobは、BigImportantClassが彼のニーズを満たすために書かれ、彼のニーズを満たしていることを保証し、彼のニーズを満たすものとして文書化されていることを保証するために、プロジェクトAを所有する人々にサインアップする必要があります。もはや彼のニーズを満たすことができないように変更されないことを保証するために配置されます。

クラスが内部であれば、そのプロセスを通過する必要はなく、プロジェクトAの予算を節約して他のものに費やすことができます。

内部のポイントは、ボブが人生を困難にするということではありません。 それは、プロジェクトAが機能、寿命、互換性などについてどのような高価な約束をしているかを制御できるようにすることです。

Question

C#のinternalキーワードには、実際にどのような用途があるのか​​説明してください。

私はinternal修飾子が現在のアセンブリへのアクセスを制限していることを知っていますが、いつ必要なのでしょうか?




私が覚えていないブログで、先日、多分週に興味深いものを見ました。 基本的に私はこれを信用できませんが、役に立つアプリケーションがあると思いました。

抽象クラスを別のアセンブリに見せたいが、他のアセンブリから継承できるようにしたくないとします。 封印されたものは理由のために抽象的であるため動作しません。そのアセンブリの他のクラスは継承します。 他のアセンブリのどこかにParentクラスを宣言したい場合があるため、Privateは動作しません。

namespace Base.Assembly
{
  public abstract class Parent
  {
    internal abstract void SomeMethod();
  }

  //This works just fine since it's in the same assembly.
  public class ChildWithin : Parent
  {
    internal override void SomeMethod()
    {
    }
  }
}

namespace Another.Assembly
{
  //Kaboom, because you can't override an internal method
  public class ChildOutside : Parent
  {
  }

  public class Test 
  { 

    //Just fine
    private Parent _parent;

    public Test()
    {
      //Still fine
      _parent = new ChildWithin();
    }
  }
}

ご覧のとおり、誰かがParentクラスを継承することなく使用することを効果的に許可します。




クラスのメンバーをinternalにするのが理にかなっている場合があります。 1つの例は、クラスのインスタンス化の方法を制御したい場合です。 クラスのインスタンスを作成するための何らかの種類のファクトリを提供しているとしましょう。 コンストラクタをinternalにして、同じアセンブリ内にあるファクトリがクラスのインスタンスを作成できるようにしますが、そのアセンブリの外部にあるコードは作成できません。

しかし、具体的な理由がなくてもクラスやメンバーをinternal作ることはできません。




この例にはAssembly1.csとAssembly2.csという2つのファイルが含まれています。 最初のファイルには、内部基本クラス、BaseClassが含まれています。 2番目のファイルで、BaseClassをインスタンス化しようとするとエラーが発生します。

// Assembly1.cs
// compile with: /target:library
internal class BaseClass 
{
   public static int intM = 0;
}

// Assembly1_a.cs
// compile with: /reference:Assembly1.dll
class TestAccess 
{
   static void Main()
   {  
      BaseClass myBase = new BaseClass();   // CS0122
   }
}

この例では、例1で使用したのと同じファイルを使用し、BaseClassのアクセシビリティ・レベルをpublicに変更します。 また、メンバIntMのアクセシビリティレベルをinternalに変更します。 この場合、クラスをインスタンス化できますが、内部メンバーにアクセスすることはできません。

// Assembly2.cs
// compile with: /target:library
public class BaseClass 
{
   internal static int intM = 0;
}

// Assembly2_a.cs
// compile with: /reference:Assembly1.dll
public class TestAccess 
{
   static void Main() 
   {      
      BaseClass myBase = new BaseClass();   // Ok.
      BaseClass.intM = 444;    // CS0117
   }
}

ソースhttp://msdn.microsoft.com/en-us/library/7c5ka91b(VS.80).aspx : http://msdn.microsoft.com/en-us/library/7c5ka91b(VS.80).aspx




publicとして定義されたクラスは、誰かがプロジェクトの名前空間を参照すると自動的にインテリセンスで表示されることに注意してください。 APIの観点からは、プロジェクトのユーザーに使用できるクラスのみを表示することが重要です。 internalキーワードを使用して、見えないものを隠すことができます。

プロジェクトAのBig_Important_Classがプロジェクト外で使用されることになっている場合は、 internalマークするべきではありません。

しかし、多くのプロジェクトでは、実際にはプロジェクト内での使用のみを目的としたクラスを持つことがよくあります。 たとえば、パラメータ化されたスレッド呼び出しの引数を保持するクラスがあるとします。 このような場合、意図しないAPIの変更から自分自身を守る以外の理由がない限り、それらをinternalとしてマークする必要があります。




internalキーワードの1つは、アセンブリのユーザーからの具体的な実装へのアクセスを制限することです。

ファクトリやオブジェクトを構築するための他の中心的な場所がある場合、アセンブリのユーザはパブリックインターフェイスまたは抽象基本クラスのみを扱う必要があります。

また、内部コンストラクタを使用すると、そうでなければパブリッククラスがインスタンス化される場所と時期を制御することができます。




大量の複雑な機能を単純なパブリックAPIにカプセル化したDLLを作成する場合、公に公開されないクラスメンバーには「内部」が使用されます。

隠蔽複雑さ(別名カプセル化)は、高品質ソフトウェアエンジニアリングの主な概念です。




あなたができる限り厳密な修飾子として使うことによって動かされることは、他のアセンブリから明示的にアクセスする必要があるまで、別のクラスのメソッドにアクセスする必要があるあらゆる場所で内部を使用します。

アセンブリインターフェイスは通常クラスインターフェイスの合計よりも狭いので、私が使用する場所は非常に多くあります。




内部クラスを使用すると、アセンブリのAPIを制限できます。 これには、APIの理解を簡単にするなどの利点があります。

また、アセンブリにバグが存在する場合、修正が大幅に変更される可能性は低くなります。 内部クラスがなければ、クラスのパブリックメンバーを変更することは大きな変更になると考える必要があります。 内部クラスを使用すると、パブリックメンバーを変更すると、アセンブリの内部API(およびInternalsVisibleTo属性で参照されるアセンブリ)のみが破損することが想定されます。

クラスレベルとアセンブリレベルでのカプセル化が好きです。 これに同意しない人もいますが、その機能が利用可能であることを知ってうれしいです。







あなたが現在のアセンブリの範囲内でアクセス可能で、決して外側にアクセスできないメソッド、クラスなどを持っているとき。

たとえば、DALにはORMがあるかもしれませんが、オブジェクトはビジネスレイヤーに公開されるべきではありません。すべての対話は、静的メソッドを介して行われ、必要なパラメーターを渡す必要があります。




Related