8

私は C# が初めてで、C++ で通常friend識別子を使用する問題があります。これで、キーワードが C# に存在しないことがわかりましたfriendが、これを回避する方法についての経験はありません (可能であれば回避したいすべてのクラス変数をパブリック プロパティにすることを除いて)。

次のシナリオがあります。

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 Info { get return A.info; set A.Info  = value; }

    /* And some more data of its own*/
}

public class C
{
    private A m_instanceOfA;

    // I need a constructor of C, which needs to set C.m_instanceOfA
    // to the same value as b.m_instanceOfA.
    public C(B b) { m_instanceOfA = b.m_instanceOfA ; } // <--- Not allowed!

    /* And some more data of its own*/
}

B.m_instanceOfA公開せずCに、この変数へのアクセスを許可する他の賢い方法はありますか(コンストラクター内のみ)?

4

6 に答える 6

9

内部

internalキーワードを使用できます。あなたの型 (または型メンバー) は、同じアセンブリ内の他の型にのみ表示されます。また:

内部型を他のアセンブリから見えるようにする必要がある場合は、 InternalsVisibleToAttributeを使用できます。この属性は、アセンブリ全体を対象とし、通常はAssemblyInfo.csファイルに書き込まれます。


PS: Friend キーワードは C# には存在しませんが、友情の概念は存在します (C++ の概念とまったく同じではありません) 。MSDNのFriend Assembliesの記事で説明されています。また、フレンド キーワードが VB.NETに存在し、C# の internal キーワードとまったく同じ動作をすることにも注意してください。

于 2013-10-02T11:39:32.243 に答える
1

「内部」キーワードを探していると思います-基本的に同じアセンブリ内のクラスにのみ表示されます

または、次のようなこともできます(メソッド名を許してください!):

public interface IAmAFriendOfB {
   void DoSomethingWithA(A instanceOfA);
}

public class B {
    private A m_instanceOfA;

    public B(A a) { m_instanceOfA = a; }

    public void BeFriendlyWith(IAmAFriendOfB friend) {
       friend.DoSomethingWithA(m_instanceOfA);
    }

    // the rest of your class
}

public class C : IAmAFriendOfB {

    private A m_instanceOfA;

    public C(B b) {
        b.BeFriendlyWith(this);
    }

    void DoSomethingWithA(A instanceOfA) {
        m_instanceOfA = b.m_instanceOfA;
    }   
}
于 2013-10-02T11:10:25.490 に答える
1

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) は、 内からのみアクセスできるシングルトン インスタンスを表しますCB.GetInstanceOfAのインスタンスが必要なため、このC.AGetter関数は の外部では役に立たなくなりCます。関数はinternal露出を最小限に抑えるようにマークされていますが、引数は、一般的な使用を意図していない自己文書化の形式としても機能する必要があります。

インターフェイスの代替案は、意図した範囲を超えてメソッドを公開するリスクがありますが (たとえば、公開されたメソッドにアクセスできないインターフェイスを実装するクラス)、このアプローチはそれを防ぎます。アクセスの否定論者はfriendまだそれに反対するかもしれませんが、これは物事を意図した範囲に近づけます。

于 2017-07-13T14:02:57.140 に答える