I am reading "C# via CLR" and on page 380, there's a note saying the following:
Note The Enum class defines a HasFlag method defined as follows
public Boolean HasFlag(Enum flag);
Using this method, you could rewrite the call to Console.WriteLine like this:
Console.WriteLine("Is {0} hidden? {1}", file, attributes.HasFlag(FileAttributes.Hidden));
However, I recommend that you avoid the HasFlag method for this reason:
Since it takes a parameter of type Enum, any value you pass to it must be boxed, requiring a memory allocation ."
I can not understand this bolded statement -- why "
any value you pass to it must be boxed
The flag
parameter type is Enum
, which is a value type, why would there be boxing? The "any value you pass to it must be boxed" should mean boxing happens when you pass value type to parameter Enum flag
, right?
Enumeration (or enum) is a value data type in C#. It is mainly used to assign the names or string values to integral constants, that make a program easy to read and maintain.
You can use extension methods to add functionality specific to a particular enum type.
The HasFlag method is designed to be used with enumeration types that are marked with the FlagsAttribute attribute and can be used to determine whether multiple bit fields are set. For enumeration types that are not marked with the FlagsAttribute attribute, call either the Equals method or the CompareTo method.
An enumeration type (or enum type) is a value type defined by a set of named constants of the underlying integral numeric type. To define an enumeration type, use the enum keyword and specify the names of enum members: C# Copy.
Since C# 7.3, where generic Enum constraint was introduced, you can write a fast, non allocating version that doesn't rely on reflection. It requires the compiler flag /unsafe but since Enum backing types can only be a fixed amount of sizes, it should be perfectly safe to do:
using System;
using System.Runtime.CompilerServices;
public static class EnumFlagExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool HasFlagUnsafe<TEnum>(TEnum lhs, TEnum rhs) where TEnum : unmanaged, Enum
{
unsafe
{
switch (sizeof(TEnum))
{
case 1:
return (*(byte*)(&lhs) & *(byte*)(&rhs)) > 0;
case 2:
return (*(ushort*)(&lhs) & *(ushort*)(&rhs)) > 0;
case 4:
return (*(uint*)(&lhs) & *(uint*)(&rhs)) > 0;
case 8:
return (*(ulong*)(&lhs) & *(ulong*)(&rhs)) > 0;
default:
throw new Exception("Size does not match a known Enum backing type.");
}
}
}
}
It's worth noting that a generic HasFlag<T>(T thing, T flags)
which is about 30 times faster than the Enum.HasFlag
extension method can be written in about 30 lines of code. It can even be made into an extension method. Unfortunately, it's not possible in C# to restrict such a method to only take things of enumerated types; consequently, Intellisense will pop up the method even for types for which it is not applicable. I think if one used some language other than C# or vb.net to write the extension method it might be possible to make it pop up only when it should, but I'm not familiar enough with other languages to try such a thing.
internal static class EnumHelper<T1>
{
public static Func<T1, T1, bool> TestOverlapProc = initProc;
public static bool Overlaps(SByte p1, SByte p2) { return (p1 & p2) != 0; }
public static bool Overlaps(Byte p1, Byte p2) { return (p1 & p2) != 0; }
public static bool Overlaps(Int16 p1, Int16 p2) { return (p1 & p2) != 0; }
public static bool Overlaps(UInt16 p1, UInt16 p2) { return (p1 & p2) != 0; }
public static bool Overlaps(Int32 p1, Int32 p2) { return (p1 & p2) != 0; }
public static bool Overlaps(UInt32 p1, UInt32 p2) { return (p1 & p2) != 0; }
public static bool Overlaps(Int64 p1, Int64 p2) { return (p1 & p2) != 0; }
public static bool Overlaps(UInt64 p1, UInt64 p2) { return (p1 & p2) != 0; }
public static bool initProc(T1 p1, T1 p2)
{
Type typ1 = typeof(T1);
if (typ1.IsEnum) typ1 = Enum.GetUnderlyingType(typ1);
Type[] types = { typ1, typ1 };
var method = typeof(EnumHelper<T1>).GetMethod("Overlaps", types);
if (method == null) method = typeof(T1).GetMethod("Overlaps", types);
if (method == null) throw new MissingMethodException("Unknown type of enum");
TestOverlapProc = (Func<T1, T1, bool>)Delegate.CreateDelegate(typeof(Func<T1, T1, bool>), method);
return TestOverlapProc(p1, p2);
}
}
static class EnumHelper
{
public static bool Overlaps<T>(this T p1, T p2) where T : struct
{
return EnumHelper<T>.TestOverlapProc(p1, p2);
}
}
EDIT: A previous version was broken, because it used (or at least tried to use) EnumHelper<T1
, T1
>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With