我怎样才能避免使用类似枚举的属性进行所有这些重复?
How could I avoid all this repetition with enumerated-like properties?
我刚刚在 class 中发现了一个由索引不匹配引起的隐蔽错误,这是由于代码重复且类似序列。
我的问题:是否有另一种更明智的方法来公开属性(与 WPF 一起用于数据绑定)而无需所有这些可怕的重复?
代码(包括对最差部分的评论):
public class MemoryTable
{
public string Name { get; private set; }
int TableNumber { get; set; }
DeviceWrapper _device;
public MemoryTable(DeviceWrapper deviceWrapper, string name, int number)
{
_device = deviceWrapper;
Name = name;
TableNumber = number;
}
public float P1
{
get { return getVal(0); }
set { setVal(0, value); }
}
public float P2
{
get { return getVal(1); }
set { setVal(1, value); }
}
public float P3 // Notice that I have three numerical values
{
get { return getVal(2); }
set { setVal(2, value); } // I typed "1" here accidentally... Bug!
}
public float P4
{
get { return getVal(3); }
set { setVal(3, value); }
}
public float P5
{
get { return getVal(4); }
set { setVal(4, value); }
}
public float P6
{
get { return getVal(5); }
set { setVal(5, value); }
}
public float P7
{
get { return getVal(6); }
set { setVal(6, value); }
}
public float P8
{
get { return getVal(7); }
set { setVal(7, value); }
}
private float getVal(int pos)
{
return _device.GetCalibrationValue(TableNumber, pos);
}
private void setVal(int pos, float val)
{
_device.SetCalibrationValue(TableNumber, pos, val);
}
internal void FillWithValue(float value)
{
P1 = value;
P2 = value;
P3 = value;
P4 = value;
P5 = value;
P6 = value;
P7 = value;
P8 = value; // "foreach" by hand, really? :o(
}
}
编辑:XAML,接受答案的建议:
<DataGrid.Columns>
<DataGridTextColumn Header="A1" Binding="{Binding [0]}" Width="100"/>
<DataGridTextColumn Header="B1" Binding="{Binding [1]}" Width="100"/>
<DataGridTextColumn Header="A2" Binding="{Binding [2]}" Width="100"/>
<DataGridTextColumn Header="B2" Binding="{Binding [3]}" Width="100"/>
<DataGridTextColumn Header="A3" Binding="{Binding [4]}" Width="100"/>
<DataGridTextColumn Header="B3" Binding="{Binding [5]}" Width="100"/>
<DataGridTextColumn Header="A4" Binding="{Binding [6]}" Width="100"/>
<DataGridTextColumn Header="B4" Binding="{Binding [7]}" Width="100"/>
</DataGrid.Columns>
您可以绑定到索引属性:
public float this[int i]
{
get { return getVal(i); }
set { setVal(i, value); }
}
在XAML中:
<!-- If MemoryTable instance is property of current data context -->
<TextBox Text="{Binding MyMemoryTable[1]}" />
<!-- If MemoryTable instance itself is current data context -->
<TextBox Text="{Binding [1]}" />
我能想到几种不同的方法,但我不是特别喜欢其中的任何一种。
一种方法是将属性实现为索引器:
public float this[int index]
{
get { return getVal(index); }
set { setVal(index, value); }
}
您需要添加范围检查,因为有人可能会尝试这样做 myObject[7]
,这是不允许的。您可以绑定到 WPF 中的索引器。这样 可能 起作用。但这确实让 class 的消费者承担了责任,因为他们不会获得属性的智能感知(因为它只是一个不可或缺的参数)。
另一个选项会涉及一些反射技巧,以获取正在设置的 属性 的名称,并使用它来确定将哪个值传递给 getVal
/setVal
。但这至少有反射和字符串解析,感觉……不对。但这类似于使用 C# 6 中的 CallerMemberNameAttribute 或 nameof
运算符。
我刚刚在 class 中发现了一个由索引不匹配引起的隐蔽错误,这是由于代码重复且类似序列。
我的问题:是否有另一种更明智的方法来公开属性(与 WPF 一起用于数据绑定)而无需所有这些可怕的重复?
代码(包括对最差部分的评论):
public class MemoryTable
{
public string Name { get; private set; }
int TableNumber { get; set; }
DeviceWrapper _device;
public MemoryTable(DeviceWrapper deviceWrapper, string name, int number)
{
_device = deviceWrapper;
Name = name;
TableNumber = number;
}
public float P1
{
get { return getVal(0); }
set { setVal(0, value); }
}
public float P2
{
get { return getVal(1); }
set { setVal(1, value); }
}
public float P3 // Notice that I have three numerical values
{
get { return getVal(2); }
set { setVal(2, value); } // I typed "1" here accidentally... Bug!
}
public float P4
{
get { return getVal(3); }
set { setVal(3, value); }
}
public float P5
{
get { return getVal(4); }
set { setVal(4, value); }
}
public float P6
{
get { return getVal(5); }
set { setVal(5, value); }
}
public float P7
{
get { return getVal(6); }
set { setVal(6, value); }
}
public float P8
{
get { return getVal(7); }
set { setVal(7, value); }
}
private float getVal(int pos)
{
return _device.GetCalibrationValue(TableNumber, pos);
}
private void setVal(int pos, float val)
{
_device.SetCalibrationValue(TableNumber, pos, val);
}
internal void FillWithValue(float value)
{
P1 = value;
P2 = value;
P3 = value;
P4 = value;
P5 = value;
P6 = value;
P7 = value;
P8 = value; // "foreach" by hand, really? :o(
}
}
编辑:XAML,接受答案的建议:
<DataGrid.Columns>
<DataGridTextColumn Header="A1" Binding="{Binding [0]}" Width="100"/>
<DataGridTextColumn Header="B1" Binding="{Binding [1]}" Width="100"/>
<DataGridTextColumn Header="A2" Binding="{Binding [2]}" Width="100"/>
<DataGridTextColumn Header="B2" Binding="{Binding [3]}" Width="100"/>
<DataGridTextColumn Header="A3" Binding="{Binding [4]}" Width="100"/>
<DataGridTextColumn Header="B3" Binding="{Binding [5]}" Width="100"/>
<DataGridTextColumn Header="A4" Binding="{Binding [6]}" Width="100"/>
<DataGridTextColumn Header="B4" Binding="{Binding [7]}" Width="100"/>
</DataGrid.Columns>
您可以绑定到索引属性:
public float this[int i]
{
get { return getVal(i); }
set { setVal(i, value); }
}
在XAML中:
<!-- If MemoryTable instance is property of current data context -->
<TextBox Text="{Binding MyMemoryTable[1]}" />
<!-- If MemoryTable instance itself is current data context -->
<TextBox Text="{Binding [1]}" />
我能想到几种不同的方法,但我不是特别喜欢其中的任何一种。
一种方法是将属性实现为索引器:
public float this[int index]
{
get { return getVal(index); }
set { setVal(index, value); }
}
您需要添加范围检查,因为有人可能会尝试这样做 myObject[7]
,这是不允许的。您可以绑定到 WPF 中的索引器。这样 可能 起作用。但这确实让 class 的消费者承担了责任,因为他们不会获得属性的智能感知(因为它只是一个不可或缺的参数)。
另一个选项会涉及一些反射技巧,以获取正在设置的 属性 的名称,并使用它来确定将哪个值传递给 getVal
/setVal
。但这至少有反射和字符串解析,感觉……不对。但这类似于使用 C# 6 中的 CallerMemberNameAttribute 或 nameof
运算符。