admin管理员组

文章数量:1122846

I'm finding a way to do sth like this in C#:

// giving eTankComponents is an [Flags] enum

[Flags]
public enum eTankComponents
{
     Empty = 0,
     Barrel = 1,
     wheels = 2,
}

Type enumType = Type.GetType("eTankComponents");
object emptyTank = Enum.Parse(enumType, "Empty");
object tankWithBarrel = Enum.AddFlag(emptyTank, enumType, Enum.Parse(enumType, "Barrel"));
object fullTank = Enum.AddFlag(tankWithBarrel, enumType, Enum.Parse(enumType, "wheels"));`

Is there any Method in c# to do sth like Enum.AddFlag

searched online and found nothing.

I'm finding a way to do sth like this in C#:

// giving eTankComponents is an [Flags] enum

[Flags]
public enum eTankComponents
{
     Empty = 0,
     Barrel = 1,
     wheels = 2,
}

Type enumType = Type.GetType("eTankComponents");
object emptyTank = Enum.Parse(enumType, "Empty");
object tankWithBarrel = Enum.AddFlag(emptyTank, enumType, Enum.Parse(enumType, "Barrel"));
object fullTank = Enum.AddFlag(tankWithBarrel, enumType, Enum.Parse(enumType, "wheels"));`

Is there any Method in c# to do sth like Enum.AddFlag

searched online and found nothing.

Share Improve this question edited Nov 22, 2024 at 15:55 gunr2171 17.4k26 gold badges66 silver badges100 bronze badges asked Nov 22, 2024 at 15:52 216 dark216 dark 31 bronze badge 4
  • 3 What does sth mean? – Bouke Commented Nov 22, 2024 at 15:58
  • 2 Please clarify your specific problem or provide additional details to highlight exactly what you need. As it's currently written, it's hard to tell exactly what you're asking. – Bouke Commented Nov 22, 2024 at 15:58
  • Well, Enum.Parse(enumType, "Barrel, wheels") will give you the combined value. But it's not clear to me why you'd need to do that. Are you trying to use reflection to update an object of an unknown type? – Richard Deeming Commented Nov 22, 2024 at 16:01
  • @RichardDeeming yes. I'm trying to make an editor with nodes outputs all kinds of Types in the Assemblies to each other. So An FlagEnumNode is designed to output an object enumValueObj of any enum which marked with attribute [Flags]. – 216 dark Commented Nov 22, 2024 at 17:21
Add a comment  | 

3 Answers 3

Reset to default 1

Sure, it's called a bitwise OR operation, or |:

    var emptyTank = (eTankComponents)Enum.Parse(enumType, "Empty");
    Console.WriteLine(emptyTank); // Empty
    
    var tankWithBarrel = emptyTank | (eTankComponents)Enum.Parse(enumType, "Barrel");
    Console.WriteLine(tankWithBarrel); // Barrel
    
    var fullTank = tankWithBarrel | (eTankComponents)Enum.Parse(enumType, "wheels");
    Console.WriteLine(fullTank); // Barrel, Wheels

There are many ways of writing the above, from reflection cast to proper types (like my example), to reflection cast to int (if you don't know the enum type statically), to dynamic code even.

You can get the underlying values using Convert.ToInt64 and use bitwise OR on them. Int64 is the largest underlying value type that an enum can have, and this will work for enums with smaller underlying value types too.

Then you can use ToObject to get the enum value from the underlying value.

Type enumType = Type.GetType("eTankComponents");
var barrel = Enum.Parse(enumType, "Barrel");
var wheels = Enum.Parse(enumType, "Wheels");
var combined = Convert.ToInt64(barrel) | Convert.ToInt64(wheels);

Console.WriteLine(Enum.ToObject(enumType, combined));

In .NET 7, I think you can come up with something like this:

public static class EnumExt {

    private static ConcurrentDictionary<Type, MethodInfo> s_dict = new();
    private static MethodInfo s_orEnumsMethodInfo = typeof(EnumExt)
        .GetMethod(nameof(OrEnums), BindingFlags.Static | BindingFlags.NonPublic);

    // Unknown type at compile time
    public static object AddFlag(Type type, object enumVal, object flagToAdd) {
        try {
            var methodInfo = s_dict.GetOrAdd(type,ValueFactory);
            return methodInfo.Invoke(null, [enumVal, flagToAdd]);
        } catch (Exception ex) {
            // TODO: make reflection exception more telling
            throw;
        }
    }

    public static T AddFlag<T>(this T enumVal, T flagToAdd)
    where T : Enum {
        return Enum.GetUnderlyingType(typeof(T)) switch {
            Type t when t == typeof(byte) => OrEnums<T, byte>(enumVal, flagToAdd),
            Type t when t == typeof(sbyte) => OrEnums<T, sbyte>(enumVal, flagToAdd),
            Type t when t == typeof(short) => OrEnums<T, short>(enumVal, flagToAdd),
            Type t when t == typeof(ushort) => OrEnums<T, ushort>(enumVal, flagToAdd),
            Type t when t == typeof(int) => OrEnums<T, int>(enumVal, flagToAdd),
            Type t when t == typeof(uint) => OrEnums<T, uint>(enumVal, flagToAdd),
            Type t when t == typeof(long) => OrEnums<T, long>(enumVal, flagToAdd),
            Type t when t == typeof(ulong) => OrEnums<T, ulong>(enumVal, flagToAdd),
            _ => throw new ArgumentException($"Unsupported underlying type {Enum.GetUnderlyingType(typeof(T)).Name}")
        };
    }

    private static MethodInfo ValueFactory(Type t) {
        var genMethod = s_orEnumsMethodInfo.MakeGenericMethod(t, Enum.GetUnderlyingType(t));
        return genMethod;
    }

    private static TEnum OrEnums<TEnum, TUnderlying>(TEnum val1, TEnum val2)
    where TUnderlying : IBitwiseOperators<TUnderlying, TUnderlying, TUnderlying> {
        var firstCast = Unsafe.As<TEnum, TUnderlying>(ref val1);
        var secondCast = Unsafe.As<TEnum, TUnderlying>(ref val2);
        var result = firstCast | secondCast;
        return Unsafe.As<TUnderlying, TEnum>(ref result);
    }
}

本文标签: cIs there a way to Add Flag enum to each other without knowing the exact enum typeStack Overflow