我怎么能避免所有这些重复使用类似枚举的属性?

时间:2015-02-06 20:28:15

标签: c# dry

我刚刚发现由于我的类中的索引不匹配而导致的一个潜在的错误,这是由于代码重复和序列化。

我的问题:是否会有另一种更明智的方式来公开属性(与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>

2 个答案:

答案 0 :(得分:4)

您可以绑定到索引属性:

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]}" />

答案 1 :(得分:1)

我可以想到几种不同的方式,但我并不特别喜欢它们。

一种方法是将属性实现为索引器:

public float this[int index]
{
    get { return getVal(index); }
    set { setVal(index, value); }
}

您需要添加范围检查,因为有人可能会尝试myObject[7]并且不应该允许这样做。{1}}您可以绑定到WPF中的索引器。这样可能工作。但它确实将责任推给了你班级的消费者,因为他们不会获得属性的智能感知(因为它只是一个不可或缺的参数)。

另一个选项会涉及一些带有反射的技巧,以获取要设置的属性的名称,并使用它来确定要传递到getVal / setVal的值。但这至少得到了反思和字符串解析,感觉......错了。但这类似于使用C#6中的CallerMemberNameAttributenameof运算符。