使用 LINQ 将一堆布尔值转换为枚举列表

本文关键字:转换 布尔值 枚举 列表 一堆 LINQ 使用 | 更新日期: 2023-09-27 18:30:41

假设我有这样的类:

class From
{
    public bool FlagOne { get; set; }
    public bool FlagTwo { get; set; }
    public bool FlagThree { get; set; }
}

。我想将这些列表转换为这些列表:

class To
{
    public List<Flag> Flags { get; set; }
}

Flag如下所示:

public enum Flag
{
    One,Two,Three
}

我写了一些代码:

var froms = new List<From>
{
    new From {
        FlagOne = false,
        FlagTwo = true,
        FlagThree = true
    },
    new From {
        FlagOne = true,
        FlagTwo = false,
        FlagThree = true
    }
};
var tos = froms.Select(from => new To {
    Flags = // ....... what?  what goes here?
}).ToList();

枚举值和布尔标志的名称无关紧要。 没有必要进行反思。

上下文

我有一个这样的数据库表:

+---------+---------+-----------+
| FlagOne | FlagTwo | FlagThree | 
+=========+=========+===========|
|    0    |    1    |     1     |
+---------+---------+-----------+
|    1    |    0    |     1     |
+---------+---------+-----------+

我想制作一个看起来像这样的 UI:

+-------------------------------------+
| Lorem blahdiblah FlagTwo, FlagThree |
+-------------------------------------+
| Lorem blahdiblah FlagOne, FlagThree |
+-------------------------------------+

不必这样做;我只是认为这是一个用 LINQ 解决的有趣问题,找不到任何答案。

使用 LINQ 将一堆布尔值转换为枚举列表

解决此问题的一种方法是在集合中使用可为空的 Flag,然后过滤掉null s,如下所示:

var tos = froms
    .Select(f => new To {
        Flags = new[] {
            f.FlagOne   ? (Flag?)Flag.One : null,
            f.FlagTwo   ? (Flag?)Flag.Two : null,
            f.FlagThree ? (Flag?)Flag.Three : null
        }
        .Where(f => f.HasValue)
        .Select(f => f.Value)
        .ToList()
     }).ToList();

在分配 Flags 中创建的数组有三个类型 Flag? 的项目 - 每个标志一个。对应于未设置属性的标志变为 null s;与设置属性对应的标志变为可为空Flag.XYZ

其余的很简单:Where()过滤掉nullSelect()删除可空性,最后ToList()使结果成为列表。

为什么要

转换它?

您也可以在枚举中实现标志:

[Flags]
public enum Foo : int {
   Bit1 = 0x01,
   Bit2 = 0x02,
   Bit3 = 0x04
}

然后,只需按位 AND 操作即可检查标志是否处于活动状态。例如:

Foo aVariable = Foo.Bit1|Foo.Bit3;//both bit1 and bit3 are enabled

检查是否启用了 bit3:

if((aVariable&Foo.Bit3) != 0x00) {
   //flag is enabled, now do something
}
else {
   //flag is disabled, do something else
}

使用这种结构的优点是位表示得更紧凑,操作(如按位 OR)可以更快地处理,并且您不必担心位的语义(枚举隐藏了位的实际值)。

如果确实要枚举可能的值,可以使用泛型构造:

public static class Bar {
  public static IEnumerable<T> EnumerateAtoms<T> (this T input) where T : enum {
    foreach(T value in Enum.GetValues(typeof(T))) {
      if((input&val) != 0x00) {
        yield return value;
      }
    }
  }
}
To ConvertFromFromToTo(From from)
{
    List<Flag> flags = new List<Flag>();
    if (from.FlagOne)   flags.Add(Flag.One);
    if (from.FlagTwo)   flags.Add(Flag.Two);
    if (from.FlagThree) flags.Add(Flag.Three);
    return new To { Flags = flags };
}
var tos = froms.Select(ConvertFromFromToTo).ToList();

目前尚不清楚您打算如何将标志布尔映射到枚举值中,但您可能希望使用这样的东西:

Flags = new List<Flag> { 
from.FlagOne ? Flag.One : Flag.Two,
from.FlagTwo ? Flag.One : Flag.Two,
from.FlagThree ? Flag.One : Flag.Two }

主要问题是您希望Flag.One,Flag.Two和Flag.III代表什么。