我要传一个IEnumerable<T>
枚举值(枚举具有 Flags 属性)并返回聚合值。下面的方法有效,但前提是枚举使用默认值 Int32
类型。如果它使用 byte
或 Int64
它不会工作。
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;
}
我知道我可以获得基础类型:
Type enumType = typeof(T);
Type underlyingType = Enum.GetUnderlyingType(enumType);
但我不知道如何在方法中使用它。我如何制作扩展方法以便它可以处理任何
enums
的列表带有标志属性?更好,但可能是非常大的 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);
}
谢谢
安德鲁
最佳答案
此解决方案将转换内联到基础类型并返回到表达式中的枚举类型。
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,struct
约束与 IsEnum
检查仍然是要走的路。
关于将枚举值的通用列表组合为单个值的 C# 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53636974/