Parse enum skipping Obsolete

How to skip obsolete values when I'm casting my int values to enums? I have minimum working example below:

using System;

public class Program
{
    public static void Main()
    {
        int valueInt = 1;
        var en = (TestObsolete)valueInt;
        Console.WriteLine(en);
    }
}

enum TestObsolete
{
    Undefined,
    [Obsolete]
    ValueA = 1,
    ValueB=1,
}

I'm getting ValueA, but expecting to get ValueB. Especially I'm interested in generic method with following signature:

public static T ParseEnumWithoutObsolete<T>(int val) where T: struct {

I tried to do something like that:

T @enum;
var enumValues = Enum.GetValues(typeof(T)).Cast<T>();
var obsoleteValues = enumValues.Where(a => typeof(T).GetField(a.ToString()).CustomAttributes.Any(t => t is ObsoleteAttribute));
var activeValues = enumValues.Except(obsoleteValues);

but stuck in the next step.

Jon Skeet
people
quotationmark

I'm getting ValueA, but expecting to get ValueB.

You're getting the value represented by the integer 1. The fact that you're seeing that as ValueA has nothing to do with Parse, and everything to do with ToString.

It's really, really important to bear in mind that when you have a value of an enum type, it's really just an integer. There can be several names for the same integer value, and they're completely indistinguishable when you've just got the value.

It sounds to me like what you really want to do - possibly in addition to your parsing method - is write a ToStringWithoutObsolete method. That could map values to names, but only for values which don't have the obsolete attribute. Note that using typeof(T).GetField(a.ToString()) anywhere in your code will make the results unpredictable. It would be better to get all the static fields within the enum type. So for example:

var valueToName = typeof(T)
    .GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
    .Where(f => !f.IsDefined(typeof(ObsoleteAttribute), false)
    .ToDictionary(f => (T) f.GetValue(null),
                  f => f.Name);

people

See more on this question at Stackoverflow