6

私が持っているやや単純なラッパークラスに少し問題があります。

次のようになります。

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 自体のインスタンスのように動作します。

例えば

Wrapper<int> foo = 42;

ただし、2 番目の Wrapper クラスの値のみを割り当てたいので、Wrapper の 1 つのインスタンスを別のインスタンスに割り当てるときに、少し問題があります。

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

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

または、プロパティを通じて _value を公開します。

ただし、これはライブラリにあり、ユーザーがこれを覚えていることに依存したくないので、代入演算子のオーバーライドを模倣する方法を知っていますか?

ポインターを変更するだけの問題 (クラス インスタンスを別のインスタンスに割り当てるときのように) は、これらの Wrapper オブジェクトへのポインターの辞書を持っているため、辞書が停止するため、それらを常に変更することができないことです。そしたらマッチング。

これがややこしいかどうかはわかります。重要なことを省略している場合は、お気軽にお問い合わせください :-)

4

8 に答える 8

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();

あなたは本当に創造的になり、いくつかの演算子をオーバーロードして、本質的に何もしないようにすることができます. ただし、それはお勧めしません。このような種類のものに演算子のオーバーロードを使用すると、通常、コードが不可解になり、多くの場合壊れます。

于 2009-03-14T05:45:23.243 に答える
3

Wrapper<T>をaにすることができますstruct。ただし、これがアプリケーションの設計に適しているかどうかはわかりません。

于 2009-03-14T02:46:28.103 に答える
1

ここで行っていることと非常によく似た処理を行う Nullable<T>... を見ると、.Value プロパティを使用して内部値が公開されています。

ポインターを変更するだけの問題 (クラス インスタンスを別のインスタンスに割り当てるときのように) は、これらの Wrapper オブジェクトへのポインターの辞書を持っているため、辞書が停止するため、それらを常に変更することができないことです。そしたらマッチング。

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

于 2009-03-13T22:37:23.600 に答える
1

ラッパーを暗黙的に両方向にキャストしないでください。

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>from からto へのキャストTは損失の多い変換であり (少なくとも、それがデータベースからの値であるという事実を失います)、ベスト プラクティスでは明示的である必要があります。DBValue<T>からにキャストしても何も失われない場合はT、 を返すプロパティを使用することもできますT

基本的に、これを行うべきではない理由は既に説明しました。DBValue を T の代わりに使用でき、その逆も可能である場合、コンパイラ (または開発者) はどの方法を選択すべきかをどのように判断するのでしょうか?

下流の開発者に次の記述を要求する:

string value = MyProperty.Value

また

string value = (string)MyProperty

それ以外の

string value = MyProperty

...それほど面倒なことではなく、何が起こっているのかを全員が正確に把握できるようにします。

編集:

実際に質問に答えるために、参照割り当てをオーバーライドすることはできません-または、あなたが持っているように見せることはできませんが、実際には必要ありません。

于 2009-03-14T13:19:13.583 に答える
0

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

または、質問を編集して、設計のより広範な説明と、この Wrapper がそれにどのように適合するかを説明してください。誰かがより簡単なアプローチを提案できる可能性があります。

于 2009-03-14T10:15:58.867 に答える
0

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

インターフェイスを使用すると、これらの関数が公開され、ロジックが完全に壊れてしまうため、使用できません。

それが役に立ったら、クラス全体を投稿できますが、それはやや長いです (130 行)。(ただし、最終的にそのサーバーから削除する可能性があるため、この質問の完全性が損なわれます)

また、完全なエッセイを書かずにクラスを説明するのは本当に難しいです :-/

とにかく、私が抱えている問題を説明しようとします。

CustomerTable と UserTable の 2 つのテーブル クラスがあるとします。

public class CustomerTable
{
  Wrapper<string> Name;
}

public class UserTable
{
  Wrapper<string> Name;
}

問題は、他の開発者が上記のコードを次のように使用する可能性があることです。

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

それが機能するために、開発者がすべきことは次のとおりです。

user.Name = (string)customer.Name;

しかし、問題は、コードを書くときに、誰がそれについて考えるでしょうか?

Value プロパティを使用したとしても、開発者は忘れずに記述する必要があります。

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

また、開発者はこれを忘れる可能性があり、突然例外が発生するか、さらに悪いことに、データベースに永続化されていないデータが発生します。

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

たくさん書いて、たくさんのコードを書きました - 書きすぎたら教えてください。

于 2009-03-14T12:30:56.353 に答える
0

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


両方の暗黙の演算子を使用して元の指定された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 クラスの使用は、クラス プロパティ コンテキストの外部で使用される場合、つまりオブジェクト間で渡される場合、依然として問題になる可能性があります。おそらく、Wrapper クラス全体を適切なクラス設計で排除できます。プロパティの set/get アクセサーの使用を含みます。

于 2014-09-09T18:44:52.120 に答える
0

AJ Lane あなたの言いたいことはわかります。その通りだと思います。ライブラリをできるだけ簡単に使用できるようにしたかっただけです。

DbValue から T への暗黙的なキャストの理由は、単に T を期待する関数のためです。

例えば

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

それよりも

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

これには、キャストが暗黙的である必要があります。

そうは言っても、これを入力しているときにあなたのコメントを読んだだけで、それがかなりの問題であることがわかります。

プロパティを介して値を公開することに戻ると思います。開発者がさらに入力する必要があるだけで、コードが見苦しくなります。

DbValue を想像してみてください:

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

しかし、繰り返しになりますが、単に読んだだけで期待とは異なる動作をするコードよりも、「醜い」コードの方がおそらく優れています。

この質問は、本当に「ベストプラクティス」の質問になると思います。

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

ご意見ありがとうございます:-)

于 2009-03-14T14:09:08.300 に答える