作り方を参照型のプロパティ"読み取り専用"
-
22-08-2019 - |
質問
私のクラス Bar
専用の格納するフィールドの参照型 Foo
.たいと思いく Foo
公共の財産もしたいと思わない、消費者の大きさを変更 Foo
...べきであるしかし一部変更できるように動作する Bar
, (いであるかのように映像化している分野 readonly
.
いうのは:
private _Foo;
public Foo
{
get { return readonly _Foo; }
}
ます---もちろん、そうではありません。ももクローンの Foo
(assummingで IClonable
がないことが明らかではないことになる。べき変更したいプロパティの名前を FooCopy
??ていくべきなので、 GetCopyOfFoo
法ょうか?うると考える最良慣行?よろしく!
解決
いるように聞こえるよ後の"const"からC++.これは存在しないクライアントまで、フルのC#.ありませんのことを示す消費者ができな変更の特性をオブジェクトが、何かできると仮定は、ひとつのメカニズムに会員に公開ました。
き返すクローンのFoo示唆されるように、または可能性がある 眺望 のFooとして ReadOnlyCollection います。もちろんだが Foo
変更不能な型には、その生活をより簡単な...
注意する必要があると大きな違いを 分野 読み取り専用のオブジェクト自体を変更できません。
現在、タイプ自体が変化も異なる相手とそれぞれのやり方でこの:
_Foo = new Foo(...);
または
_Foo.SomeProperty = newValue;
ければニーズができるように、第二に、ティなのかも分かるようにすると読み取り専用すが、問題が人々を取得財産できる変異のオブジェクトです。ければ必要最初に、実際に Foo
のいずれかで不変なのでまたはあなたの不変なので、できるだけ提供する、視認性の高いビルだけの"ゲッター"があります。
この 非常に重要な ご理解の違いを変更する価値の分野で別のインスタンス)の内容を変更するオブジェクトの分野をさします。
他のヒント
残念ながら、現時点ではC#で、この周りの簡単な方法はありません。あなたはあなたの財産のリターンの代わりFoo
のをインタフェースにFoo
の「読み取り専用の一部」を抽出してみましょうことができます。
、ReadOnlyCollection
をコピーを作る、またはFoo
は不変であるあなたは既に推測してきたように、通常3つの最良のルートです。
私は時々の代わりに、私は単純に関与しているどのくらいの作業に応じて、基になるフィールドを返すよりも大きな何かをやっている時はいつでもプロパティのメソッドを好みます。方法は、何かが起こっていることを意味するもので、彼らはあなたのAPIを使用している際に、消費者のためのフラグの多くを上げます。
受け取ったり返したりする Foo オブジェクトの「クローン作成」は、と呼ばれる通常の行為です。 防御的なコピー. 。クローン作成によってユーザーに見える目に見えない副作用がない限り、これを行わない理由はまったくありません。多くの場合、特に C# や Java では、これがクラスの内部プライベート データを保護する唯一の方法です。 const
利用できません。(IE、これら 2 つの言語で真に不変のオブジェクトを適切に作成するには、これを行う必要があります。)
明確にするために、考えられる副作用としては、ユーザーが元のオブジェクトが返されることを (合理的に) 期待していることや、Foo によって保持されているリソースが正しく複製されないことなどが考えられます。(この場合、IClonable を実装して何をしているのでしょうか?!)
あなたは誰があなたの状態を台無しにしたくない場合は...それを公開しないでください!他の人が言ったように、何かがあなたの内部の状態を表示する必要がある場合、それの不変の表現を提供します。また、クライアントはを伝えるために取得しますの代わりに、それ自体を行うので、(「聞かないで伝える」ためのGoogleの)何かをしています。
ジョンスキートのコメントを明確にするためにビューを作ることができ、それは変更可能Fooのための不変のラッパークラスです。ここでは例があります:
class Foo{
public string A{get; set;}
public string B{get; set;}
//...
}
class ReadOnlyFoo{
Foo foo;
public string A { get { return foo.A; }}
public string B { get { return foo.B; }}
}
あなたが実際にC#でC ++のconstの動作を再現することができます - あなただけのそれを手動で行う必要があります。
。が何であれFoo
、呼び出し側がその状態を変更することができる唯一の方法は、上のメソッドを呼び出すか、プロパティを設定することである。
例えば、Foo
は型FooClass
である
class FooClass
{
public void MutateMyStateYouBadBoy() { ... }
public string Message
{
get { ... }
set { ... }
}
}
あなたのケースでは、あなたがそれらをMessage
プロパティを取得するが、それを設定しないようにするために満足している、とあなたは間違いなく彼らはそのメソッドを呼び出すことについて満足していないので。
そこで彼らが行うことに許されているものを記述したインタフェースを定義します:
interface IFooConst
{
public string Message
{
get { ... }
}
}
私たちは、変異の方法を残し、唯一のプロパティのゲッターに残してきています。
次にFooClass
のベースリストにそのインターフェイスを追加します。
今Foo
プロパティを使用してクラスで、あなたはフィールドを持っています:
private FooClass _foo;
とプロパティのゲッターます:
public IFooConst Foo
{
get { return _foo; }
}
これは基本的にC ++ const
キーワードを自動的に行うだろう正確にどのような手で再現します。擬似C ++用語では、型const Foo &
の参照のみFoo
部材としてマークされたconst
のメンバーを含んで自動的に生成されたタイプのようなものです。 C#のいくつかの理論的な将来のバージョンにこれを翻訳、あなたはこのようFooClass
を宣言したい:
class FooClass
{
public void MutateMyStateYouBadBoy() { ... }
public string Message
{
get const { ... }
set { ... }
}
}
本当に私がやったすべてが新しいIFooConst
キーワードと1人の安全なメンバーをタグ付けすることによって、バックFooClass
にconst
の情報をマージしています。そうな方法で、constキーワードを追加すると、このパターンに正式なアプローチ以外の言語に多くを追加しないでしょう。
そして、あなたはconst
オブジェクトへのFooClass
参照を持っていた場合:
const FooClass f = GetMeAFooClass();
あなたが唯一f
上のconstメンバーを呼び出すことができるでしょう。
FooClass
定義が公開されている場合、呼び出し側がIFooConst
にFooClass
を唱えられることに注意してください。それは「const
を離れてキャスト」と呼ばれ、const_cast<T>(const T &)
と呼ばれる特殊な作業を必要とするの
あなたの製品のバージョン間で進化することは非常に容易ではないインターフェースの問題もあります。第三者があなたが(彼らはそれを見ることができれば、彼らが行うことは自由である)を定義するインターフェイスを実装することができる場合は、そのコードを再コンパイルするために他人を必要とせず、将来のバージョンではそれに新しいメソッドを追加することはできません。あなたが構築するために他の人のための拡張可能なライブラリを作成している場合でも、それが唯一の問題です。たぶんビルトインconst
機能は、この問題を解決するだろう。
私は、同様のセキュリティの事を考えていました。方法はおそらくあります。非常に明確ではなく、短いです。一般的な考え方は非常に簡単です。しかし、私は常にいくつかの方法が周りので、それをテストしたことはありません発見しました。しかし、あなたはそれをチェックすることができ - 多分それはあなたのために動作します。
。これは擬似コードですが、私はその背後にある考え方は明らかであると思います。
public delegate void OnlyRuller(string s1, string s2);
public delegate void RullerCoronation(OnlyRuller d);
class Foo {
private Foo();
public Foo(RullerCoronation followMyOrders) {
followMyOrders(SetMe);
}
private SetMe(string whatToSet, string whitWhatValue) {
//lot of unclear but private code
}
}
あなたはSetMeメソッドへのアクセス権を持ってこのプロパティを作成しますが、fooがunmutableに見える作成者以外のように、それはまだプライベートのクラスでとてもます。
は、まだいくつかのプロパティよりも大きい何のためにこれはおそらく、すぐにスーパー混乱になっただろう - 私は常にカプセル化の他の方法を好適な理由です。しかし、あなたは、これは一つの代替であるよりも、クライアントは、Fooの変更を許可しないようにするために、それは超重要だ場合。
私が言ったように、ただし、これは理論だけです。