2

I have the following;

public static bool Has<T>(this System.Enum type, T value) where T : struct
{
    return (((int)(ValueType)type & (int)(ValueType)value) == (int)(ValueType)value);
}

For some reason, calling this extension method is generating garbage, and I simply can't see why. Everything here is struct or values. Where is that unseen garbage? Is there some not-so-obvious boxing going on? Is there a better way to do this extension method?

LightStriker
  • 19,738
  • 3
  • 23
  • 27

1 Answers1

4

Casting to ValueType effectively boxes the object (note that ValueType, while the "base class for value types", is a class), and then the cast to int unboxes it. This will also fail if the underlying type of the enum happens to be something other than Int32, which is also possible.

You should be able to use Enum.HasFlag to accomplish this same functionality without a custom method.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • I'm stuck in .NET <3.5, which does not have Enum.HasFlag. Is there an alternative that would not involve boxing? – LightStriker Jul 18 '14 at 18:20
  • Take a look at this thread http://stackoverflow.com/questions/4108828/generic-extension-method-to-see-if-an-enum-contains-a-flag – Etienne Maheu Jul 18 '14 at 18:29
  • @EtienneMaheu Sadly, using Convert to turn an Enum into a ulong also generates garbage. I have a feeling I'm going to be stuck with it. – LightStriker Jul 18 '14 at 18:35
  • What do you mean by "garbage"? What kind of "garbage" do you get? This code works perfectly well for me so I find it strange that it does not work in your case. Can you post your enum's definition? – Etienne Maheu Jul 18 '14 at 18:35
  • @EtienneMaheu I never said it's not working, it's working perfectly fine! I mean garbage as in what the Garbage Collector eats for breakfast; object instances with no references towards them. – LightStriker Jul 18 '14 at 18:41
  • 2
    Note that `Enum.HasFlag` will still generate some garbage because its argument is of type `System.Enum` which is a class and so the argument will be boxed. – Mike Zboray Jul 18 '14 at 18:43
  • 1
    @LightStriker Just going to Enum will create some garbage. That's pretty much part of life with this.. – Reed Copsey Jul 18 '14 at 18:49
  • @mikez True - though it doesn't do as many boxes and unboxes as this, from what I recall – Reed Copsey Jul 18 '14 at 18:50
  • Well the link I shared use decompiled code from the .NET framework so I would expect the native HasFlag method to be as boxing-intensive as this version. – Etienne Maheu Jul 18 '14 at 18:51
  • 2
    @EtienneMaheu Current framework handles this in native code to make it better. See: http://referencesource.microsoft.com/#mscorlib/system/enum.cs#820 – Reed Copsey Jul 18 '14 at 18:54
  • Well, thanks for all the information. From what I understand, I simply cannot avoid generating garbage from an extension method for an Enum, I can only try to minimized it. I guess I'll have to live with it. – LightStriker Jul 18 '14 at 18:54
  • @ReedCopsey I count three boxes here (although it could be two if a local variable is used). Looking at the reference source, I see another box for `this.GetType()` so that's two boxing operations for each call to `Enum.HasFlag`. – Mike Zboray Jul 18 '14 at 18:57
  • @LightStriker There is no good way to do it in general. However, you might consider writing extension methods on the specific enums where you have memory pressure/performance concerns. – Mike Zboray Jul 18 '14 at 18:59
  • @LightStriker and/or just use normal methods ;) – Reed Copsey Jul 18 '14 at 20:41