internal
シングルトン インスタンスを持つクラスを使用する別の方法を次に示します。これにより、疑似クラスprivate
に公開されるメソッドを微調整できます。friend
using System;
namespace Test
{
public class A
{
public string Info { get; set; }
/* much more data */
}
public class B
{
private A m_instanceOfA;
public B(A a) { m_instanceOfA = a; }
public string Info
{
get { return m_instanceOfA.Info; }
set { m_instanceOfA.Info = value; }
}
// requires an instance of a private object, this establishes our pseudo-friendship
internal A GetInstanceOfA(C.AGetter getter) { return getter.Get(m_instanceOfA); }
/* And some more data of its own*/
}
public class C
{
private A m_instanceOfA;
private static AGetter m_AGetter; // initialized before first use; not visible outside of C
// class needs to be visible to B, actual instance does not (we call b.GetInstanceOfA from C)
internal class AGetter
{
static AGetter() { m_AGetter = new AGetter(); } // initialize singleton
private AGetter() { } // disallow instantiation except our private singleton in C
public A Get(A a) { return a; } // force a NullReferenceException if calling b.GetInstanceOfA(null)
}
static C()
{
// ensure that m_AGetter is initialized
System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(typeof(AGetter).TypeHandle);
}
public C(B b)
{
m_instanceOfA = b.GetInstanceOfA(m_AGetter);
}
public string Info
{
get { return m_instanceOfA.Info; }
set { m_instanceOfA.Info = value; }
}
/* And some more data of its own*/
}
public class Test
{
public static void Main()
{
A a = new A();
B b = new B(a);
C c = new C(b);
c.Info = "Hello World!";
Console.WriteLine(a.Info);
}
}
}
ライブデモ
クラスはそれ自体のC.AGetter
外部でインスタンス化できないため、C.m_AGetter
( と の両方private
であるstatic
) は、 内からのみアクセスできるシングルトン インスタンスを表しますC
。B.GetInstanceOfA
のインスタンスが必要なため、このC.AGetter
関数は の外部では役に立たなくなりC
ます。関数はinternal
露出を最小限に抑えるようにマークされていますが、引数は、一般的な使用を意図していない自己文書化の形式としても機能する必要があります。
インターフェイスの代替案は、意図した範囲を超えてメソッドを公開するリスクがありますが (たとえば、公開されたメソッドにアクセスできないインターフェイスを実装するクラス)、このアプローチはそれを防ぎます。アクセスの否定論者はfriend
まだそれに反対するかもしれませんが、これは物事を意図した範囲に近づけます。