這是我的做法,這是類型安全的,不會做任何拳或拆箱。如果該類型不是枚舉,則會引發異常。 如果你想將它變成一個公共的靜態方法,你可以使用這種方法,這種方法將被輸入到Enum的方法中,但是它不能作爲擴展方法。 也不需要檢查null,因爲struct contraint也會阻塞可爲null的枚舉。我認爲除了可能用F#或C++/CLI編寫代碼之外,還有很多工作可以改進這些代碼,這樣您就可以對它施加枚舉約束。 的想法是使用表達式目錄樹,將枚舉轉換爲建立一個函數或者長如果任何東西,但基於ULONG枚舉或ulong,然後和他們基本上是生產:: return value & flag == flag
public static class EnumExtensions
{
#region Public Static Methods
/// <summary>
/// Determines whether the specified value has flags. Note this method is up to 60 times faster
/// than the one that comes with .NET 4 as it avoids any explict boxing or unboxing.
/// </summary>
/// <typeparam name="TEnum">The type of the enum.</typeparam>
/// <param name="value">The value.</param>
/// <param name="flag">The flag.</param>
/// <returns>
/// <c>true</c> if the specified value has flags; otherwise, <c>false</c>.
/// </returns>
/// <exception cref="ArgumentException">If TEnum is not an enum.</exception>
public static bool HasFlags<TEnum>(this TEnum value, TEnum flag) where TEnum:struct,IComparable,IConvertible,IFormattable
{
return EnumExtensionsInternal<TEnum>.HasFlagsDelegate(value, flag);
}
#endregion Public Static Methods
#region Nested Classes
static class EnumExtensionsInternal<TEnum> where TEnum : struct,IComparable, IConvertible, IFormattable
{
#region Public Static Variables
/// <summary>
/// The delegate which determines if a flag is set.
/// </summary>
public static readonly Func<TEnum, TEnum, bool> HasFlagsDelegate = CreateHasFlagDelegate();
#endregion Public Static Variables
#region Private Static Methods
/// <summary>
/// Creates the has flag delegate.
/// </summary>
/// <returns></returns>
private static Func<TEnum, TEnum, bool> CreateHasFlagDelegate()
{
if(!typeof(TEnum).IsEnum)
{
throw new ArgumentException(string.Format("{0} is not an Enum", typeof(TEnum)), typeof(EnumExtensionsInternal<>).GetGenericArguments()[0].Name);
}
ParameterExpression valueExpression = Expression.Parameter(typeof(TEnum));
ParameterExpression flagExpression = Expression.Parameter(typeof(TEnum));
ParameterExpression flagValueVariable = Expression.Variable(Type.GetTypeCode(typeof(TEnum)) == TypeCode.UInt64 ? typeof(ulong) : typeof(long));
Expression<Func<TEnum, TEnum, bool>> lambdaExpression = Expression.Lambda<Func<TEnum, TEnum, bool>>(
Expression.Block(
new[] { flagValueVariable },
Expression.Assign(
flagValueVariable,
Expression.Convert(
flagExpression,
flagValueVariable.Type
)
),
Expression.Equal(
Expression.And(
Expression.Convert(
valueExpression,
flagValueVariable.Type
),
flagValueVariable
),
flagValueVariable
)
),
valueExpression,
flagExpression
);
return lambdaExpression.Compile();
}
#endregion Private Static Methods
}
#endregion Nested Classes
}
正如我忘了上面的表達式樹是.NET 4只以下的方法應該工作在.NET 3.5創建同一表達式樹::
private static Func<TEnum, TEnum, bool> CreateHasFlagDelegate2()
{
if(!typeof(TEnum).IsEnum)
{
throw new ArgumentException(string.Format("{0} is not an Enum", typeof(TEnum)), typeof(EnumExtensionsInternal<>).GetGenericArguments()[0].Name);
}
ParameterExpression valueExpression = Expression.Parameter(
typeof(TEnum),
typeof(TEnum).Name
);
ParameterExpression flagExpression = Expression.Parameter(
typeof(TEnum),
typeof(TEnum).Name
);
var targetType = Type.GetTypeCode(typeof(TEnum)) == TypeCode.UInt64 ? typeof(ulong) : typeof(long);
Expression<Func<TEnum, TEnum, bool>> lambdaExpression = Expression.Lambda<Func<TEnum, TEnum, bool>>(
Expression.Equal(
Expression.And(
Expression.Convert(
valueExpression,
targetType
),
Expression.Convert(
flagExpression,
targetType
)
),
Expression.Convert(
flagExpression,
targetType
)
),
valueExpression,
flagExpression
);
return lambdaExpression.Compile();
}
這個版本應該在編譯.NET 3.5,如果沒有我不明白爲什麼。
可能是有趣的:http://stackoverflow.com/questions/7244/anyone-know-a-good-workaround-for-the-lack-of-an-enum-generic-constraint – 2010-11-05 18:34:36
它可能是一個好主意標記這與您正在使用的C#版本,因爲最新版本內置此功能。 – chilltemp 2010-11-05 18:42:38
我不明白'Contains'方法如何添加任何內容的實例方法'Enum.HasFlag(枚舉)'。查看該方法的反編譯代碼,您的方法看起來正在做同樣的事情,只需少量的錯誤檢查。 – 2012-10-07 14:31:40