【问题标题】:Efficient way to split enum flags to create distinct items in collection拆分枚举标志以在集合中创建不同项目的有效方法
【发布时间】:2015-09-09 16:11:28
【问题描述】:

我有一个这样的收藏:

IEnumerable<RecordToSend> recordsToSend;

由以下组成:

public class RecordToSend {
    public Guid ApplicationId { get; set; }
    public ScheduleTypes Schedule { get; set; }
}

并标记枚举:

[Flags]
public enum ScheduleTypes
{
    None = 0,
    Daily = 1,
    Weekly = 2,
    Monthly = 4
}

假设我有以下集合,它基本上是使用实体框架查询从数据库中提取出来的:

| ApplicationId | Schedule |
| ABC123        | 7        |
| DEF456        | 3        |

什么是将枚举拆分为多个不同记录的有效方法,从而导致这种情况(可以使用RecordToSend 类或其他类型,如果有意义的话,甚至是动态的):

| ApplicationId | Schedule |
| ABC123        | 1        |
| ABC123        | 2        |
| ABC123        | 4        |
| DEF456        | 1        |
| DEF456        | 2        |

注意 ScheduleTypes 枚举有一个 0 值标志,我想在结果中忽略它。

效率并不是最重要的问题,尽管我很想听听对不同方法的性能的看法。如果在我将集合从数据库中拉出时,作为实体框架查询的一部分,可以在一个步骤中执行此拆分,那就太好了。在应用程序中,我不需要处于原始多值状态的枚举标志。

【问题讨论】:

    标签: c# .net enums split flags


    【解决方案1】:

    这应该可行。

    var results = records.SelectMany(
        r => Enum.GetValues(typeof(ScheduleTypes))
                 .Cast<ScheduleTypes>()
                 .Where(e => e != ScheduleTypes.None && r.Schedule.HasFlag(e))
                 .Select(e => 
                     new RecordToSend
                     {
                         Guid = r.Guid, 
                         Schedule = e
                     }));
    

    基本上对于每条记录,它都会遍历可能的枚举值(跳过 0 值)并检查 Schedule 是否具有该标志。然后使用相同的Guid 和枚举标志创建一条新记录。然后SelectMany 将创建的记录集合展平。

    请注意,如果 records 是 IQueryable,则必须添加 AsEnumerable,因为我怀疑这会转化为 SQL。

    【讨论】:

    • 太棒了,谢谢!我会试试这个并报告。基本上正是我在寻找它的声音,并且不确定要深入研究的高级概念。
    • 再次感谢您的帮助!这基本上正是我所需要的。我确实必须进行一些转换才能使其真正与我的代码一起使用(不确定这是否特定于我的代码)所以我想在这里提出修改建议,如果它们有意义,你可以接受它们。
    • 你是对的。 Enum.GetValues 返回Array,您需要转换这些值。我已经通过在它后面添加Cast&lt;ScheduleTypes&gt;() 来解决这个问题。
    【解决方案2】:

    试试 linq

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data;
    
    namespace ConsoleApplication1
    {
        class Program
        {
    
            static void Main(string[] args)
            {
                IEnumerable<RecordToSend> recordsToSend = new List<RecordToSend>() {
                    new RecordToSend() { ApplicationId = System.Guid.Parse("00000001-0001-0001-0001-000000000123"), Schedule = ScheduleTypes.Daily},
                    new RecordToSend() { ApplicationId = System.Guid.Parse("00000001-0001-0001-0001-000000000123"), Schedule = ScheduleTypes.Weekly},
                    new RecordToSend() { ApplicationId = System.Guid.Parse("00000001-0001-0001-0001-000000000123"), Schedule = ScheduleTypes.Monthly},
                    new RecordToSend() { ApplicationId = System.Guid.Parse("00000001-0001-0001-0001-000000000456"), Schedule = ScheduleTypes.Daily},
                    new RecordToSend() { ApplicationId = System.Guid.Parse("00000001-0001-0001-0001-000000000456"), Schedule = ScheduleTypes.Weekly}
                };
    
                var results = recordsToSend.AsEnumerable()
                    .GroupBy(x => x.ApplicationId)
                    .Select(x => new {
                        ApplicationID = x.Key, 
                        Schedule = x.Select(y => (int)y.Schedule).Sum()
                     }).ToList();
    
            }
        }
        [Flags]
        public enum ScheduleTypes
        {
            None = 0,
            Daily = 1,
            Weekly = 2,
            Monthly = 4
        }
        public class RecordToSend
        {
            public Guid ApplicationId { get; set; }
            public ScheduleTypes Schedule { get; set; }
        }
    }
    ​
    

    【讨论】:

    • 这是合并,而不是分离。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-14
    • 1970-01-01
    相关资源
    最近更新 更多