4

私は次のタイプを持っています:

// incomplete class definition
public class Person
{
    private string name;

    public string Name
    {
        get { return this.name; }
    }
}

このタイプをある種の専用コントローラー/ビルダーで作成および更新したいのですが、他のタイプに対しては読み取り専用のままにしておきたいです。

このオブジェクトは、コントローラー/ビルダーによって更新されるたびにイベントを発生させる必要もあります。

要約すると、前の型定義スケルトンによると:

  • Person特定のコントローラによってのみインスタンス化できます
  • このコントローラーは、 (フィールド)の状態をいつでも更新できます。Personname
  • 発生時に世界中に通知Personを送信する必要性
  • 他のすべてのタイプは、属性の読み取り のみ可能にする必要がありますPerson

これをどのように実装すればよいですか? ここではコントローラー/ビルダーについて話していますが、他のすべてのソリューションは大歓迎です。

注:修飾子に頼ることができますがinternal、理想的にはすべてのものを同じアセンブリにする必要があります。

4

6 に答える 6

5

getアクセサーのみを公開するインターフェイスIReadOnlyPersonを作成します。PersonにIReadOnlyPersonを実装してもらいます。Personへの参照をコントローラーに保存します。他のクライアントに読み取り専用バージョンのみを提供します。

これにより、ほとんどのOO機能と同様に、間違いから保護されますが、詐欺からは保護されません。クライアントは、IReadOnlyPersonがPersonによって実装されていることを知っている(または疑って​​いる)場合、Personにランタイムキャストできます。

コメントごとに更新:

読み取り専用インターフェースは、他のオブジェクトと同様に、イベントデリゲートを公開する場合もあります。C#で一般的に使用されるイディオムは、クライアントがリスナーのリストをいじるのを防ぐことはできませんが、慣例ではリスナーを追加するだけなので、それで十分です。状態が変化する副作用のあるセットアクセサーまたは関数の内部では、null(リスナーなし)の場合のガードを使用してイベントデリゲートを呼び出すだけです。

于 2008-09-17T19:39:35.013 に答える
1

インターフェイスIPersonとネストされたクラスを使用します。

public class Creator
{
    private class Person : IPerson
    {
        public string Name { get; set; }
    }

    public IPerson Create(...) ...


    public void Modify(IPerson person, ...)
    {
        Person dude = person as Person;
        if (dude == null)
            // wasn't created by this class.
        else
            // update the data.
    }
}
于 2008-09-17T19:38:09.137 に答える
1

読み取り専用のインターフェイスが好きです。次に、ビルダー/コントローラー/何でもオブジェクトを直接参照できますが、このオブジェクトを外部に公開すると、インターフェイスのみが表示されます。

于 2008-09-17T19:34:31.733 に答える
1

internalは、これが最も簡単で最善のアプローチだと思います (もちろん、これには複数のアセンブリが含まれます)。プロパティ セッターで呼び出し元を特定するために、オーバーヘッドが集中するスタック ウォーキングを実行する以外に、次のことを試すことができます。

interface IPerson 
{
    Name { get; set; } 
}

このインターフェイスを明示的に実装します。

class Person : IPerson 
{
    Name { get; private set; }
    string IPerson.Name { get { return Name; } set { Name = value; } } 
}

次に、プロパティを設定するためにビルダーで明示的なインターフェイス キャストを実行します。これはまだ実装を保護するものではなく、意図を強調する方法にはなりますが、良い解決策ではありません。

プロパティ セッターでは、イベント通知を実装する必要があります。この問題に自分自身でアプローチするには、プロパティごとに個別のイベントとイベント ハンドラーを作成するのではなく、代わりに単一の PropertyChanged イベントを作成し、変更が発生したときに各プロパティで発生させます (イベント引数には、プロパティ名、古い値、および新しい値が含まれます)。 )。

于 2008-09-17T19:48:09.050 に答える
1

Person オブジェクトの名前を変更することはできませんが、そのコントローラーをつかんでそこで変更することはできます。これは、オブジェクトのデータを保護する良い方法ではありません。

しかし、それにもかかわらず、これを行う方法は次のとおりです。

    /// <summary>
    /// A controlled person.  Not production worthy code.
    /// </summary>
    public class Person
    {
        private string _name;
        public string Name
        {
            get { return _name; }
            private set
            {
                _name = value;
                OnNameChanged();
            }
        }
        /// <summary>
        /// This person's controller
        /// </summary>
        public PersonController Controller
        {
            get { return _controller ?? (_controller = new PersonController(this)); }
        }
        private PersonController _controller;

        /// <summary>
        /// Fires when <seealso cref="Name"/> changes.  Go get the new name yourself.
        /// </summary>
        public event EventHandler NameChanged;

        private void OnNameChanged()
        {
            if (NameChanged != null)
                NameChanged(this, EventArgs.Empty);
        }

        /// <summary>
        /// A Person controller.
        /// </summary>
        public class PersonController
        {
            Person _slave;
            public PersonController(Person slave)
            {
                _slave = slave;
            }
            /// <summary>
            /// Sets the name on the controlled person.
            /// </summary>
            /// <param name="name">The name to set.</param>
            public void SetName(string name) { _slave.Name = name; }
        }
    }
于 2008-09-17T20:00:17.537 に答える
0

多分そのようなもの?

public class Person
{
    public class Editor
    {
        private readonly Person person;

        public Editor(Person p)
        {
            person = p;
        }

        public void SetName(string name)
        {
            person.name = name;
        }

        public static Person Create(string name)
        {
            return new Person(name);
        }
    }

    protected string name;

    public string Name
    {
        get { return this.name; }
    }

    protected Person(string name)
    {
        this.name = name;
    }
}

Person p = Person.Editor.Create("John");
Person.Editor e = new Person.Editor(p);
e.SetName("Jane");

きれいではありませんが、うまくいくと思います。または、エディターでSetXメソッドの代わりにプロパティを使用することもできます。

于 2008-09-17T19:41:45.990 に答える