从其子类初始化 C# Tuple 以在 WPF 中使用

本文关键字:以在 WPF 初始化 子类 Tuple | 更新日期: 2023-09-27 18:32:13

我有一个表示范围列表的对象。我正在按如下方式实现它:

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,>' 不包含接受 0 个参数的构造函数

即使添加一个简单的 no-args 构造函数也会导致相同的错误出现两次。现在提醒我,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 都是关于无参数构造函数的 gaga,所以我认为这是因为ObservableCollection希望能够初始化其Tuple<T, T>而它不能。

我不需要Tuple<T, T>课那么多;我知道我可以在SelectiveOutputRange<T>类中添加两个类型 T 的字段并调用它一天。

但是出于我的好奇心,有没有办法在 WPF ObservableCollection中使用 Tuple ?还是这里发生了其他奇怪的事情?

从其子类初始化 C# Tuple<T、T> 以在 WPF 中使用

由于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>的地方可用,请将隐式转换运算符添加到类中,返回 SelectiveOutputRange 对象中包含的 Range 属性。

如果未提供任何构造函数,编译器将假定存在不包含参数和主体的构造函数,并且它调用不提供参数的基类型的构造函数。

如果您提供自己的构造函数,但没有指定基构造函数(您的第二个示例),则假定存在对基类构造函数的调用,该构造函数不带参数。

由于Tuple<T1, T2>没有这样的构造函数,因此会出现错误。

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

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

以下代码应该可以工作(或其他答案),但在这种形式下它几乎没用。 我的建议是根本不使用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;
    }
}

很简单,你可以解决不可变性问题 - 但这是一种愚蠢的编写代码的方式,它涉及的工作与正确做代码一样多。正确的做法是定义一个新的可变类,具有有意义的属性名称和默认构造函数(以及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 世界中的所有内容都必须与其他所有内容完美配合。实在是太多了。

你应该调用基构造函数:

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;
    }
}