可以按位或枚举。通常,这是在Flags枚举上完成的。
例如var foo = MyEnum.ABC | MyEnum.XCN
我尝试使用泛型创建一个将枚举数组转换为组合枚举的方法。
以下是我的尝试:
private T CombineFlags<T>(params T[] flags) where T : struct, IConvertible
{
return flags.Select(flag => flag).Aggregate((x, y) => x | y);
}
但是,我无法应用运算符&#39; \&#39; T和T. Casting似乎没有帮助。 struct, IConvertible
似乎是最接近枚举的,但显然不够接近使用&#39; |&#39;运营商。 System.Enum也不是很有帮助。
如何在通用枚举上执行此操作? (有可能吗?)
答案 0 :(得分:2)
无法对类型为Enum
的类型应用泛型约束,或者应用类型重载|
运算符的约束,因此您执行的任何操作都可以通过必要性,将无法保持完全静态的打字。
您可以做的是将枚举更改为其基础整数类型,执行聚合,然后将其强制转换。问题是你不能(轻松)解决动态确定底层类型并执行按位或在该类型上执行(同样由于缺少对具有|
运算符重载的类型的约束)。如果您可以假设枚举的基础类型是int
(或任何较小的类型),那么您可以这样做,但如果枚举的基础类型是long
,则此代码将打破。还有一个事实是非枚举值可以用于T
,并且这些类型在传递给此方法时可能会或可能无法正常运行。
private static T CombineFlags<T>(params T[] flags) where T : struct, IConvertible
{
int n = flags.Select(flag => Convert.ToInt32(flag))
.Aggregate((x, y) => x | y);
return (T)(object)n;
}
答案 1 :(得分:2)
您可以创建一个静态辅助方法,为您的聚合生成所需的Or
函数。该功能在首次访问时生成,并缓存以供其他用途使用。
这假设传递的类型是枚举。
public T CombineFlags<T>(params T[] flags)
where T : struct, IConvertible
{
return flags.Select(flag => flag).Aggregate(EnumHelper<T>.OrFunction);
}
private class EnumHelper<T>
where T : struct,IConvertible
{
static readonly Type typeofT = typeof(T);
static readonly Type underlyingType = Enum.GetUnderlyingType(typeofT);
static readonly ParameterExpression[] parameters =
{
Expression.Parameter(typeofT),
Expression.Parameter(typeofT)
};
static readonly Func<T, T, T> _orFunc = Expression.Lambda<Func<T, T, T>>(
Expression.Convert(Expression.Or(
Expression.Convert(parameters[0], underlyingType),
Expression.Convert(parameters[1], underlyingType)
), typeofT), parameters).Compile();
public static Func<T, T, T> OrFunction { get { return _orFunc; } }
}