从其子类初始化 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 构造函数也会导致相同的错误出现两次。现在提醒我,Item1
和 Item2
是正式只读的(因为构造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
?还是这里发生了其他奇怪的事情?
由于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;
}
}