C# 将两个值映射到一个对象

C# 将两个值映射到一个对象,c#,.net-3.5,data-structures,C#,.net 3.5,Data Structures,我正在尝试用C#编写一个函数,它将接受两个小的int值(范围0-3),并根据这些值返回一个Color对象。问题在于,无法通过编程方式根据这两个值确定颜色,它们是特定于LED类型的,必须硬编码 我能想到的最简单的方法是一个大规模(16个案例)if-else语句,它将检查每个值,但这似乎不是一个非常优雅的解决方案。有没有更好的方法来确定颜色?作为使用if/else的一种稍微干净的替代方法,您可以将颜色值放置在一个数组中,并将两个小的int值作为索引放入数组中。如果您想采用OO方法(无论好坏),可以使

我正在尝试用C#编写一个函数,它将接受两个小的int值(范围0-3),并根据这些值返回一个
Color
对象。问题在于,无法通过编程方式根据这两个值确定颜色,它们是特定于LED类型的,必须硬编码


我能想到的最简单的方法是一个大规模(16个案例)if-else语句,它将检查每个值,但这似乎不是一个非常优雅的解决方案。有没有更好的方法来确定颜色?

作为使用
if
/
else
的一种稍微干净的替代方法,您可以将颜色值放置在一个数组中,并将两个小的int值作为索引放入数组中。

如果您想采用OO方法(无论好坏),可以使用元组->颜色映射:

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}
};
Dictionary d=newdictionary()
{
{Tuple.Create(2,1),Color.Red},
{Tuple.Create(1,1),Color.Blue},
{Tuple.Create(1,2),Color.Green}
};

与二维数组相比,它的一个优点是可以稀疏,而不需要空值。也可以使用集合初始值设定项,而无需按索引顺序初始化。如果您尝试对两种颜色使用相同的元组,则在初始化时会抛出一个明显的
ArgumentException

二维颜色对象数组如何

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

避免一堆
if-else
语句的首选方法是使用
Switch
。您还可以使用
枚举
并分配与小整数对应的整数值:

public enum ColorChoice
{
  red = 01 //'01' instead of '1' to make clear your first digit is zero
  blue = 02
  green = 03
  ...etc...
]

我为16种颜色投票

enum Color
{
    red = 0,
    blue = 1
}

public Color GetColor(int v1, int v2)
{
    int colorValue = v1 << 8;
    colorValue |= v2;
    return (Color)colorValue;
}
枚举颜色
{
红色=0,
蓝色=1
}
公共颜色GetColor(int v1,int v2)
{
int colorValue=v1如何:

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];
}
静态颜色GetColor(int c1,int c2)
{
如果(c1>3 | | c1<0 | | c2>3 | | c2<0)
抛出新ArgumentOutOfRangeException();
var-map=新字典
{
{“00”,颜色。黑色},
{“10”,颜色为红色},
{“20”,颜色,蓝色},
//等等,等等。。。
{“11”,颜色。浅灰色},
};
var key=c1.ToString()+c2.ToString();
返回映射[键];
}

事实上,这两个小整型值组合在一起表示某种东西(至少是一种颜色),这对我来说意味着定义一个结构来封装它们可能是有意义的

这样做的好处是,您可以使用struct作为字典的键: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];
    }
}
struct MyStruct
{
专用字节X;
专用字节_Y;
公共MyStruct(字节x,字节y)
{
_X=X;
_Y=Y;
}
公共字节X{get{return}X;}
公共字节Y{get{return}Y;}
私有静态字典_ColorMap;
静态MyStruct()
{
_ColorMap=新字典();
//从某处读取颜色映射…可能是特定于LED类型的文件
}
公共颜色GetColor()
{
返回_ColorMap[this];
}
}

这如何解决他处理两个输入参数以解析颜色的问题?@kirk Woll-上次我检查时,您可以通过其索引调用枚举值。因此,输入“0,1=>”1=>ColorChoice.Red。这实际上更容易理解(因此也更容易维护)比许多需要实际数学转换的解决方案要好。您可以将整数强制转换为枚举。但您必须在某个时间点进行数学转换。例如,如何执行3,1->orange。根据您的方案,它显然是orange=31,这需要数学(10*x+y)。此外,您应该注意01实际上是一个八进制文字;它恰好不会影响这里的结果。此外,C#enum不能有任何字段或方法,因此您可能需要另一个ColorChoice->Color mapping。使用乘法器真的是最可读的语法吗?我怀疑这会让许多程序员陷入困境。我可以用bitshift代替d、 但是我认为这会让一个单独的程序员子集离开..1当每个范围变为0-4时会发生什么?枚举的整个初始化会发生变化,公式和所有内容也会发生变化。聪明,但一点都不实用。@drharris:现在安全地过了0-4,如果有新的opti,公式和枚举值不会改变ons添加到LED上。如果您选择阵列路线,多维或锯齿阵列肯定比手动实现乘法器要好。唯一的缺点是少量计数以检查映射是否正确,如果需要稀疏映射则为空。这确实是我所需要的,但我也喜欢Matthew的建议l、 不幸的是,我使用的是.NET 3.5,它不支持元组类。谢谢大家。我不知道为什么这一个会被否决。这是唯一正确处理稀疏性的解决方案,也是所有解决方案中最可扩展的。您可以非常轻松地将其扩展到3变量的情况,并且可以轻松地增加或减少变量范围(以及有不同的范围)。根本不值得投反对票。