C#将枚举值的通用列表组合为单个值的方法 [英] C# Method to combine a generic list of enum values to a single value

查看:51
本文介绍了C#将枚举值的通用列表组合为单个值的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想传递枚举值的 IEnumerable< T> (枚举具有Flags属性)并返回合计值.下面的方法有效,但仅当枚举使用默认的 Int32 类型时.如果它使用 byte Int64 ,则将不起作用.

I want to pass a IEnumerable<T> of enum values (enum has the Flags attribute) and return the aggregate value. The method below works but only if the enum uses the default Int32 type. If it uses byte or Int64 it won't work.

public static T ToCombined<T>(this IEnumerable<T> list) where T : struct
{
    if (!typeof(T).IsEnum)
        throw new ArgumentException("The generic type parameter must be an Enum.");
    var values = list.Select(v => Convert.ToInt32(v));
    var result = values.Aggregate((current, next) => current | next);
    return (T)(object)result;
}

我知道我可以得到底层类型:

I know I can get the underlying type:

Type enumType = typeof(T);
Type underlyingType = Enum.GetUnderlyingType(enumType);

但是我看不到如何在方法中使用它.如何制作扩展方法,以便它可以处理带有flags属性的任何 enums 的列表?

but I don't see how to make use of it in the method. How can I make the extension method so it can handle a list of any enums with the flags attribute?

更好,但对于大型UInt可能是个问题

Better but might be a problem with really big UInts

public static T ToCombined<T>(this IEnumerable<T> list) where T : struct
{
    if (!typeof(T).IsEnum)
        throw new ArgumentException("The generic type parameter must be an Enum.");
    var values = list.Select(v => Convert.ToInt64(v));
    var result = values.Sum();
    var underlyingType = Enum.GetUnderlyingType(typeof(T));
    return (T)Convert.ChangeType(result, underlyingType);
}

谢谢安德鲁

推荐答案

此解决方案将转换内联到表达式中的基础类型和枚举类型.

This solution inlines the conversions to the underlying type and back to the enum type in an expression.

public static T ToCombined<T>(this IEnumerable<T> list)
    where T : Enum
{
    Type underlyingType = Enum.GetUnderlyingType(typeof(T));

    var currentParameter = Expression.Parameter(typeof(T), "current");
    var nextParameter = Expression.Parameter(typeof(T), "next");

    Func<T, T, T> aggregator = Expression.Lambda<Func<T, T, T>>(
        Expression.Convert(
            Expression.Or(
                Expression.Convert(currentParameter, underlyingType),
                Expression.Convert(nextParameter, underlyingType)
                ),
            typeof(T)
            ),
        currentParameter,
        nextParameter
        ).Compile();

    return list.Aggregate(aggregator);
}

请注意,我已经使用了C#7.3 Enum 类型约束.如果您不使用C#7.3,则使用 IsEnum 检查的 struct 约束仍然是解决方法.

Note that I've used the C# 7.3 Enum type constraint. If you're not using C# 7.3, the struct constraint with the IsEnum check is still the way to go.

这篇关于C#将枚举值的通用列表组合为单个值的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆