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 个参数的构造函数

即使添加一个简单的无参数构造函数也会导致相同的错误出现两次。现在我被提醒了,Item1并且Item2是正式只读的(作为构造的首选方式Tuple是 through 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 完全是关于无参数构造函数的,所以我认为这是因为ObservableCollection希望能够初始化它Tuple<T, T>的 s 而它不能。

我在课堂上不需要那么多Tuple<T, T>;我知道我可以在类中添加两个类型T的字段SelectiveOutputRange<T>并收工。

但是为了我的好奇,有没有办法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

当您不提供任何构造函数时,编译器假定存在一个不包含参数且不包含主体的构造函数,并且它调用不提供参数的基类型的构造函数。

如果您提供自己的构造函数但未指定基构造函数(您的第二个示例),则假定对基类的构造函数进行了不带参数的调用。

由于Tuple<T1, T2>没有这样的构造函数,你会得到一个错误。

只需创建一个接受参数并调用两个参数基构造函数的构造函数:

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 上面有一个类似但更优雅的 kludge。

元组不是为了与 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 回答