1

範囲のリストを表すオブジェクトがあります。次のように実装しています。

public class SelectiveOutputRangeCollection<T> : ObservableCollection<SelectiveOutputRange<T>> {
    public bool CanAdd() {
        return (this.Count < SelectiveOutputWindow.MaxNumberOfRanges);
    }
}

public class SelectiveOutputRange<T> : Tuple<T, T> {
    public override string ToString() {
        return this.Item1 + " to " + this.Item2;
    }
}

これはコンパイルされません:
'System.Tuple<T, T>' には、0 引数を取るコンストラクターが含まれていません

単純な引数なしのコンストラクターを追加しても、同じエラーが 2 回表示されます。そして今、私はItem1Item2が正式に読み取り専用であることを思い出しました ( を構築するための好ましい方法は を使用するためTupleですTuple.Create<T, T>())。

public class SelectiveOutputRange<T> : Tuple<T, T> {         // <-- error here
    public SelectiveOutputRange() {                          // <-- error here
        this.Item1 = default(T);                             // <-- field is read only 
        this.Item2 = default(T);                             // <-- field is read only 
    }

    public override string ToString() {
        return this.Item1 + " to " + this.Item2;
    }
}

私は、WPFが引数なしのコンストラクターについてすべてガガであることを知ってObservableCollectionTuple<T, T>ます。

Tuple<T, T>クラスからはあまり必要ありません。Tタイプの 2 つのフィールドをSelectiveOutputRange<T>クラスに追加するだけで、1 日で済むことはわかっています。

しかし、私の好奇心のためTupleに、 WPF で sを使用する方法はありますObservableCollectionか? それとも、ここで何か他の奇妙なことが起こっていますか?

4

5 に答える 5

4

は不変であるためTuple<,>、意味のあるデータで初期化できるコンストラクターを追加する必要があります。

public SelectiveOutputRange(T a, T b) : base(a, b) {
}

そのようなコンストラクターがないと、Tuple構造は使用できなくなります。

Tuple変更可能にしたい場合は、この状況での封じ込めを優先する必要があります。

class SelectiveOutputRange<T> {
    public Tuple<T,T> Range {get;private set;}
}

SelectiveOutputRange<T>必要な場所で使用できるようにしたい場合はTuple<T,T>、暗黙的な変換演算子をクラスに追加して、オブジェクトRange内に含まれるプロパティを返します。SelectiveOutputRange

于 2013-09-20T16:30:56.543 に答える
2

コンストラクターを指定しない場合、コンパイラーは、引数も本体も含まないコンストラクターが存在し、引数を提供しない基本型のコンストラクターを呼び出すと想定します。

独自のコンストラクターを提供するが、基本コンストラクターを指定しない場合 (2 番目の例)、引数を取らない基本クラスのコンストラクターへの呼び出しがあると想定されます。

そのTuple<T1, T2>ようなコンストラクタがないため、エラーが発生します。

引数を受け取り、2 つの引数の基本コンストラクターを呼び出すコンストラクターを作成するだけです。

public class SelectiveOutputRange<T> : Tuple<T, T> 
{      
    public SelectiveOutputRange(T first, T second):base(first, second) 
    {         

    }
}
于 2013-09-20T16:31:25.137 に答える
2

次のコード (または他の回答) は機能するはずですが、この形式ではほとんど役に立ちません。私のアドバイスは、まったく使用Tupleしないことです。Item1 と Item2 は無意味な変数名であるため、正直なところ、あまり有用なクラスではありません。

public class SelectiveOutputRange<T> : Tuple<T, T> {
    public SelectiveOutputRange() 
        : base(default(T), default(T))
    {
    }

    public override string ToString() {
        return this.Item1 + " to " + this.Item2;
    }
}
于 2013-09-20T16:31:43.307 に答える
2

非常に簡単に言えば、不変性の問題を回避することはできますが、コードを書くのはばかげた方法であり、正しく行うのと同じくらい多くの作業が必要です。正しいことは、意味のあるプロパティ名と既定のコンストラクター (および INotifyPropertyChanged など) を持つ新しい可変クラスを定義することです。

しかし、それはあなたの好奇心のためだけなので...

class foo
{
    public foo()
    {
    }
    public int bar = 0;
}

class footu : Tuple<foo, foo>
{
    public footu()
        : base(new foo(), new foo())
    {
    }
}

...

footu ft = new footu();

ft.Item1.bar = 0;

無意味ですが、コンパイルして動作します。dasblinkenlight には、上に似ていますが、より優雅なクラッジがあります。

Tuple は、WPF で使用するために作成されたものではありません。.NET の世界のすべてが他のすべてのものと完全に連携する必要はありません。すべてが多すぎます。

于 2013-09-20T16:41:39.523 に答える
1

基本コンストラクターを呼び出す必要があります。

public class SelectiveOutputRange<T> : Tuple<T, T>
{
    public SelectiveOutputRange(T item1, T item2)
        : base(item1, item2)
    {
    }

    public SelectiveOutputRange() : base(default(T), default(T))
    {
    }

    public override string ToString()
    {
        return this.Item1 + " to " + this.Item2;
    }
}
于 2013-09-20T16:31:19.403 に答える