2009-03-13 12 views
5

私は多少単純なラッパークラスに少し問題があります。代入演算子(=)をオーバーライドするC#模倣

それはこのようなものになります。

public class Wrapper<T> 
{ 
    private T _value; 

    public Wrapper<T>(T value) 
    { 
    _value = value; 
    } 

    public static implicit operator Wrapper<T>(T value) 
    { 
    return new Wrapper<T>(value); 
    } 

    public static implicit operator T(Wrapper<T> value) 
    { 
    return value._value; 
    } 
} 

を私はTからとの暗黙のコンバータをオーバーライドしてきたので、それはほとんどT自体のインスタンスのように動作します。

別のラッパーの1つのインスタンスを割り当てるとき、私は唯一の二ラッパークラスの値を割り当てるため、

Wrapper<int> foo = 42; 

は、しかし、私は、若干の問題を持っています。

Wrapper<int> foo = 42; 
Wrapper<int> bar = (int)foo; 

またはプロパティを通じて公的_valueを公開:

だから今、私はこれをしなければなりません。

しかし、これはライブラリにあるので、ユーザーがこれを覚えておく必要はありません。どのように代入演算子をオーバーライドすることができますか?

ポインタを変更するだけで問題になるのは(クラスインスタンスを別のインスタンスに割り当てるときと同じように)、これらのWrapperオブジェクトへのポインタの辞書があるため、すべて変更することはできません辞書はそれから一致を止めるでしょう。

これはやや混乱している場合、私は、あなたが非常にないのNullable <T> ...見れば

+0

これはこれまでに解決されましたか?私は同様の問題を抱えています - 私は基本的な型をラップするものを作成しています。フロートして、MyTypeを実行できるようにしたい< float > a = 1f; a = 2f;新しいインスタンスを作成せずに...参照は実際に魔法によって更新されますか?私は試してみたいと思いますが、それはうまくいっていると確信していません。なぜなら、うまくいくとわかっていれば盲目になるからです。 – jheriko

答えて

1

:-)お気軽にお尋ねくださいうち重要なものを残してきたので、もし私が、見ることができますここで行っていることと同様のことですが、.Valueプロパティを使用して内部値を公開します。

ポインタを変更するだけで(クラスインスタンスを別のクラスに割り当てるときと同じように)、これらのWrapperオブジェクトへのポインタの辞書があるため、すべてを変更することはできません辞書はそのときに一致を止めるからです。

私はこれに従っているかどうかは確かではありませんが、正確には辞書に保存していますか?参照を格納する場合、CLRは参照を必要に応じて更新するためです。

+1

Nullable は、これらの種類の割り当てをカバーするために、シナリオ。 – ajlane

3

あなたはラッパーを<T>のstructにすることができます。しかし、これがアプリケーションの設計に合っているかどうかはわかりません。

5

代入演算子はオーバーロードできないため、本当に良い解決策はありません。他の人が指摘しているように、構造体を使用すると、必要な代入セマンティクスが得られますが、値の意味に直面していることがよくあります。

1つのオプションは、コンストラクタをオーバーロードすることです。この構文につながる

public Wrapper(Wrapper<T> w) 
{ 
    _value = w._value; 
} 

Wrapper<int> foo = 42; 
Wrapper<int> bar = new Wrapper<int>(foo); 

あなたが持っているものよりも、より詳細な、それは良く読みますが。

それとも、書くことができるようにあなたは、Clone方法(ないICloneableインタフェース)を追加することができます。

Wrapper<int> bar = foo.Clone(); 

あなたが本当に創造的な取得と、それは、本質的に何もしない作り、いくつかの演算子をオーバーロードできます。しかし、私はそれをお勧めしません。そのような種類のもののために演算子のオーバーロードを使用すると、通常、コードが暗号を崩し、しばしば中断します。

0

これはプロパティの対象です。割り当てによってどのような意味があるかを定義することができます。クラスや構造体のために定義することはできません。なぜなら、必要なことを行うために言語によって定義されているからです。クラスにValueプロパティを追加するだけです。

質問を編集して、より包括的なデザインの説明と、このWrapperがどのようにそれに適合するかを、誰かがより簡単な方法を提案できるようにすることができます。

0

クラスを構造化するのは実際にはオプションではありません。パラメータのないコンストラクタにいくつかのロジックがあり、内部抽象関数を含む抽象クラスを継承するためです。

私はインターフェイスを使うことはできません。そうすれば、それらの関数をパブリックにすることができ、ロジックを完全に破壊することになります。

これは参考になるかもしれませんが、やや長いです(130行) それは良いでしょうか?とにかく/

私がしようとするでしょう - :

また、完全なエッセイを書くことなく、クラスがあり、本当に難しい説明(それはこの質問の整合性を痛いのに、と私はそのサーバーから最終的にそれを削除する場合があります)私が持っている問題を示しています。

CustomerTable customer = new CustomerTable(); 
UserTable user = new UserTable(); 
user.Name = customer.Name; // This breaks my internal dictionary 

開発者が行っていたはずです何:今、問題は次のようにいくつかの他の開発者は、上記のコードを使用することである

public class CustomerTable 
{ 
    Wrapper<string> Name; 
} 

public class UserTable 
{ 
    Wrapper<string> Name; 
} 

:CustomerTableとUSERTABLE:

は2つのテーブルクラスを想定します、それが働くために、でした:

user.Name = (string)customer.Name; 

問題はありますか彼らの正しい考え方で、コードを書くときにそれについて考えるだろうか?

私はValueプロパティを使用している場合でも、開発者はまだ

user.Name = customer.Name.Value; // or user.Name.Value = .... 

を書くことを覚えなければならないだろうそして再び、開発者はこれを忘れることができ、彼は例外、または悪化し、突然のすべて:データをどのデータベースに永続化されません。

私の問題は本当に、私はラッパーを完全に透明にしたいということです(実際にはラップしているクラス/プリミティブのように使えるはずです)。 しかし、あるラッパーから別のラッパーに割り当てるとき、私の内部ロジックは壊れます。

多くの文章やコードがたくさんありますが、私が文章を誇張したら教えてください。

+2

私はValueプロパティを使用します。暗黙的に型を両方向にキャストすることは、決して良い考えではありません。ダウンストリームの開発者は、単純な割り当てがコンパイルに失敗した場合に、ライブラリを正しく使用する方法を非常に迅速に学習します。 – ajlane

0

ラッパーを暗黙的に両方向にキャストしないでください。 DBValue<T>からTへのキャスト

public class DBValue<T> 
{ 
    public static implicit operator DBValue <T>(T value) 
    { 
     return new DBValue<T>(value); 
    } 

    public static explicit operator T(DBValue <T> dbValue) 
    { 
     return dbValue.Value; 
    } 

    private readonly T _value; 
    public T Value { get { this._value; } } 

    public DBValue(T value) 
    { 
     this._value = value; 
    } 
} 

は非可逆変換(最小として、あなたはそれがデータベースから値だという事実を失う)である、とベストプラクティスによって、明示的でなければなりません。 DBValue<T>からTにキャストして何かを失うことがない場合は、Tを返すプロパティを使用することもできます。

基本的には、これをやろうとしてはいけない理由はすでにわかっています.DBValueをTと置き換えてコンパイラ(または開発者)がどのように選択するのかを知る方法は?書き込みにダウンストリームの開発者が必要な

string value = MyProperty.Value 

または

string value = (string)MyProperty 

代わりの

string value = MyProperty 

...すべてが面倒ではない、とことを確認します誰もが何が起こっているのか正確に知っています。

EDIT:

実際の質問に答えるために、あなたは参照の割り当てを変更することはできません - またはあなたが持っているようにそれが見えるように - しかし、あなたは本当にする必要はありません。

+0

私はこの事実を数回は自分自身で数回してしまったことに気づくべきです。これは、とりわけ数値の問題を引き起こしました。つまり、myValueがdouble型にキャストされるクラスであれば、1 + myValueの型は何ですか? – ajlane

0

A Jレーン私はあなたが何を意味しているかを確信しています。私はあなたが正しいと思う - 私はライブラリを使用するためにできるだけシンプルにしたかった。

TへDbValueからの暗黙的なキャスト理由は、例えばT.

を期待単に機能

literalSomething.Text = Server.HtmlEncode(SomeTable.SomeStringColumn); 

なく

literalSomething.Text = Server.HtmlEncode((string)SomeTable.SomeStringColumn); 

であるこれは、へのキャストを必要とします暗黙的である。

これは私があなたのコメントを読んでいる間に、これをタイプしていると言われています。それはかなり問題です。

私はプロパティを介して価値を公開することに戻ってきます。それは単に開発者がより多くの情報を入力する必要があり、ちょっとしたコードが醜いと思います。

if (someValue.Value.HasValue) // someValue is DbValue<int?> 

をしかし、その後、再び、それはあなたが単にそれを読んで期待するものとは異なる動作コードよりも、おそらくより良い「醜い」コードとは:

ちょうどDbValueから想像してみてください。

私はこの質問が本当に「ベストプラクティス」の問題に終わると思います。

結論として、私はValueプロパティを作成し、暗黙的なキャストの代わりにそのプロパティを使用します。ライブラリを使用する開発者はそれだけで生き残る必要があります。

入力いただきありがとうございます。

+0

読みやすい(あまり「醜い」)コードでは、いつでもintを割り当てることができますか?値= someValue.Value;期待どおりに進んでください。 – ajlane

0

この古い投稿は、完了するために追加情報が必要です。 =演算子はオーバーロードできず、同様にC#をオブジェクトにキャストして独自の型にキャストすることはできないため、元の目的の動作を達成できないことは明らかです。クラス参照の割り当てには常に沸騰します。しかしSteffenのさらなる記事では、Wrapperクラスはローカル変数だけでなく、クラスフィールドタイプとして使用されていることが示されています。 パブリックフィールドの代わりにクラスプロパティを使用して、目的のセマンティクスを使用し、内部ディクショナリの整合性を維持できます。


でもその暗黙の事業者の両方で、元の与えられたWrapper<T>クラスを保ち、ここに働くだろうコードは次のとおりです。

public class CustomerTable 
{ 
    private Wrapper<string> _Name; 
    public Wrapper<string> Name { 
     get { return _Name; } 
     set { _Name = (string)value; } 
    } 
} 

public class UserTable 
{ 
    private Wrapper<string> _Name; 
    public Wrapper<string> Name { 
     get { return _Name; } 
     set { _Name = (string)value; } 
    } 
} 

この変更が行われた場合、それはまだ可能であるため、それは既存のコードを壊さないだろうプロパティを設定する様々なモード:

CustomerTable customer = new CustomerTable(); 
UserTable user = new UserTable(); 

user.Name = customer.Name; //*** No longer breaks internal data structures 

user.Name = "string literal"; // Works as expected with implicit cast operator 
user.Name = (string)customer.Name; // Still allowed with explicit/implicit cast operator 
user.Name = customer.Name.Value; // Also works if Value property is still defined 

これはまだ、ラッパーの使用を元の質問に答えていないのでおそらくWrapperクラス全体が、プロパティセット/ getアクセサの使用を含む適切なクラスデザインで削除される可能性があります。

関連する問題