将两个值映射到一个对象中

3
我正在尝试编写一个C#函数,该函数将获取两个小的int值(范围为0-3),并基于这些值返回一个Color对象。问题在于,无法通过编程方式确定颜色,因为它们是特定于LED类型的,并且必须硬编码。最简单的方法可能是使用一个庞大的if-else语句(16种情况)来检查每个值,但这似乎不是一个很优雅的解决方案。是否有更好的方法来确定颜色?
7个回答

2

如果您想采用面向对象的方法(好或坏),您可以使用元组->颜色映射:

Dictionary<Tuple<int, int>, Color> d = new Dictionary<Tuple<int, int>, Color>()
{
  {Tuple.Create(2, 1), Color.Red},
  {Tuple.Create(1, 1), Color.Blue},
  {Tuple.Create(1, 2), Color.Green}
};

相比二维数组,元组的一个优点是可以不用空值而实现稀疏存储。你还可以使用集合初始化器,而不必按索引顺序进行初始化。如果尝试将同一元组用于两种颜色,则在初始化时会明显抛出ArgumentException异常。


不确定为什么这个被踩了。这是唯一一个正确处理稀疏性并且最具可扩展性的解决方案。你可以非常容易地将其扩展到三变量情况,并且可以轻松增加或减少变量范围(以及拥有不同的范围)。完全不值得被踩。 - drharris

2

那么一个颜色对象的二维数组怎么样?

Color[,] colors = new[,] {
    { Color.FromArgb(1, 2, 3), Color.FromArgb(3, 4, 5), Color.FromArgb(6, 7, 8), Color.FromArgb(9, 10, 11) },
    { Color.FromArgb(21, 22, 23), Color.FromArgb(23, 24, 25), Color.FromArgb(26, 27, 28), Color.FromArgb(29, 30, 31) },
};

Color color = colors[index1, index2];

如果你选择使用数组,那么多维数组或者不规则数组肯定比手动实现乘法器要好。唯一的缺点是需要进行小量计数以检查映射是否正确,另外如果需要稀疏映射则可能出现空值。 - Matthew Flaschen
这对于我的需求来说已经足够了,但我也喜欢Matthew的建议。不幸的是,我正在使用不支持元组类的.NET 3.5。谢谢大家。 - Nate

1
作为使用 if / else 的略微更清洁的替代方案,您可以将颜色值放在数组中,并使用两个小 int 值作为索引来访问数组。

0

我为16种颜色投票一个枚举

enum Color
{
    red = 0,
    blue = 1
}

public Color GetColor(int v1, int v2)
{
    int colorValue = v1 << 8;
    colorValue |= v2;
    return (Color)colorValue;
}

使用乘法器真的是最易读的语法吗?我怀疑这会让许多程序员望而却步。 - Kirk Woll
我可以使用位移操作来代替,但我认为这会让一部分程序员感到困惑。 - Jimmy Hoffa
-1 当每个范围变为0-4时会发生什么?整个枚举的初始化都会改变,公式和一切都会改变。聪明,但完全不实用。 - drharris
@drharris:现在安全地通过了0-4,如果将来添加了新的LED选项,公式和枚举值也不会改变。 - Jimmy Hoffa

0

这样怎么样:

static Color GetColor(int c1, int c2)
{
  if (c1 > 3 || c1 < 0 || c2 > 3 || c2 < 0)
    throw new ArgumentOutOfRangeException();

  var map = new Dictionary<string, Color>
  {
    {"00", Color.Black},
    {"10", Color.Red},
    {"20", Color.Blue},
    // etc, etc...
    {"11", Color.DimGray},
  };

  var key = c1.ToString() + c2.ToString();
  return map[key];
}

0

你有这两个小整数值,它们结合在一起意味着某些东西(至少是颜色),这表明你可能需要定义一个结构体来封装它们。

这样做的好处是,你可以使用该结构体作为字典的键:Equals和GetHashCode方法应该已经足够工作。

以下是一个示例。由于你提到颜色无法计算,我在需要填充字典的地方留下了注释;你可以硬编码这个,但最好从文件或嵌入式资源中读取值。

编辑:更新了我的示例结构体为不可变的。

struct MyStruct
{
    private byte _X;
    private byte _Y;

    public MyStruct(byte x, byte y)
    {
        _X = x;
        _Y = y;
    }

    public byte X { get { return _X; } }
    public byte Y { get { return _Y; } }

    private static Dictionary<MyStruct, Color> _ColorMap;

    static MyStruct()
    {
        _ColorMap = new Dictionary<MyStruct, Color>();

        // read color mapping from somewhere...perhaps a file specific to the type of LED
    }

    public Color GetColor()
    {
        return _ColorMap[this];
    }
}

-3
避免使用大量的if else语句的首选方法是使用Switch。您还可以使用枚举并分配与您的小整数对应的int值:
public enum ColorChoice
{
  red = 01 //'01' instead of '1' to make clear your first digit is zero
  blue = 02
  green = 03
  ...etc...
]

2
这如何解决他处理两个输入参数以解析颜色的问题? - Kirk Woll
@kirk Woll - 上次我检查时,您可以通过索引调用枚举值。因此,输入“0,1”=>“1”=>ColorChoice.Red。这实际上比许多需要实际数学转换的解决方案更容易理解(因此更易于维护)。 - AllenG
您可以将整数转换为枚举。但是在某个时候,您需要进行数学转换。例如,如何将3,1转换为橙色。根据您的方案,似乎应该是orange = 31,这需要数学计算(10 * x + y)。此外,您还应该注意,01实际上是一个八进制字面量;它只是碰巧在这里不影响结果。另外,C#枚举不能有任何字段或方法,因此您可能需要另一个ColorChoice->Color映射。 - Matthew Flaschen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接