-1

In C# I want to be able to write

FooEnum f = fromValue(typeof(FooEnum), 42);

where fromValue returns MyEnum and FooEnum extends MyEnum.

I am converting some Java code to C#. The Java code has

  static <T extends MyEnum> T fromValue(Class<T> c, int value) { 
      return (T)fromInnerValue(c, value);
  }

This means that if we can write

  FooEnum f = fromValue(FooEnum.class, 42);

Which will return a FooEnum without the need for an explicit casts. (This happens a lot so is worthwhile.) It is "unchecked" in the narrow sense that if fromInnerValue was to return a BarEnum instead of a FooEnum we would get a runtime cast exception instead of a compile time one.

In C#/.Net System.Type does not appear to be generic. So the function definition becomes

  static T fromValue<T>(System.Type c, int value) where T : Enum {
      return (T)fromInnerValue(c, value);
  }

That compiles, but with Type rather than Type, so it does not really know what T is at compile time. Then a call

  FooEnum f = fromValue(typeof(FooEnum), 42);

fails with "Type cannot be inferred from its arguments".

  FooEnum f = fromValue<FooEnum>(typeof(FooEnum), 42);

works but has the verbosity I am trying to avoid. I think it means that fromValue has an actual run time parameter T as there is no type erasure in C#. But we have the type as that first parameter, c. But it needs to somehow be the Generic type.

Or can we go the other way in C# and make FooEnum f = fromValue(42); work?

(If it cannot be done then I would be inclined to forget about Generics and just write

FooEnum f = (FooEnum)fromInnerValue(typeof(FooEnum), 42); )

Thoughts?

Tuntable
  • 3,276
  • 1
  • 21
  • 26
  • 1
    Enum in c# is not a class but a special construct. It seems a little like you are going down the wrong track – TheGeneral Mar 11 '21 at 10:48
  • 1
    Can you show what `fromInnerValue` does? I'm surprised that `(T)fromInnerValue(c, value);` compiles. Also, why does `MyEnum` change to `Enum` in the C# version? – Sweeper Mar 11 '21 at 10:50
  • 1
    Try `static T fromValue(int value) where T : Enum { return (T)fromInnerValue(typeof(T), value); }`. You can call it with `FooEnum f = fromValue(42);` – SomeBody Mar 11 '21 at 10:54
  • "Which will return a FooEnum without the need for an explicit casts" - what is `(T)fromInnerValue(c, value)` then? Seems pretty darn explicit to me... – Ian Kemp Mar 11 '21 at 10:54
  • 1
    Anyway, assuming you are using an actual enum ,just cast... it can't be easier (myenum)42... unless you want to validate it – TheGeneral Mar 11 '21 at 10:55
  • FooEnum is not and Enum; otherwise it would have been called Enum if it was an Enum! But FooEnum is a Java Enum like object, but unlike Java it is extensible at runtime. – Tuntable Mar 12 '21 at 23:48

2 Answers2

0

Unless there is something special going on you should just be able to just do a cast

var f = (FooEnum)42;

If you absolutely want a generic method it should be possible to use

public static T FromValue<T>(int value) where T :  Enum
        => (T)Enum.ToObject(typeof(T), value);

See how to cast an int to an enum

JonasH
  • 28,608
  • 2
  • 10
  • 23
  • typeof(T) is the trick. My compile-time-generics-only Java mindset prevented me from thinking of that. – Tuntable Mar 12 '21 at 23:46
  • FooEnum is not and Enum; otherwise it would have been called Enum if it was an Enum! But FooEnum is a Java Enum like object, but unlike Java it is extensible at runtime. – Tuntable Mar 12 '21 at 23:47
0

If I understood you correctly, you have an int that you want to cast to an enum member.

Let me explain the problem.
In java an enum is a class, so you cant cast (rightfully) an int to a class.
In .NET an enum is also a class, but its values are primitives (ValueType).
The default type of an enum item is int. You can refer to this question for more information.

And since a .NET enum is an it, you can simply do

MyEnum val = (MyEnum) 42;

A compile time error wont raise here because if you pass BarEnum instead of FooEnum it will still work (and even run),
all enums are int basiclly (unless specified otherwise).

If for some reason you still want to go with the generic way, you can throw you own exception by checking if the value is defined in the enum.

static FromValue<T>(int value) where T : enum
{
  if(!Enum.IsDefined<T>(value))
     throw new Exception("This is awkward ..."); // HANDLE VALUE NOT BELONG TO ENUM
  return (T) value;
}
Br4infreze
  • 342
  • 3
  • 11
  • Enum in c# is not a class no matter which way you spin it. Just saying. Anyway the rest was good – TheGeneral Mar 11 '21 at 11:06
  • FooEnum is not and Enum; otherwise it would have been called Enum if it was an Enum! But FooEnum is a Java Enum like object, but unlike Java it is extensible at runtime. – Tuntable Mar 12 '21 at 23:48