我想通过一个IEnumerable<T>
枚举值(枚举具有 Flags 属性)并返回聚合值。下面的方法有效,但仅当枚举使用默认值时Int32
类型。如果它使用byte
or 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
与标志属性?
更好,但对于非常大的 UInt 可能会出现问题
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.3Enum
类型约束。如果您不使用 C# 7.3,struct
约束与IsEnum
检查仍然是要走的路。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)