1

I got a class in C# that has multiple overloads for different parameter types:

class Writer
{
  public Writer Write(bool value)
  {
    // Do something with value
    return this;
  }
  public Writer Write(double value)
  {
    // Do something with value
    return this;
  }
  public Writer Write(int value)
  {
    // Do something with value
    return this;
  }
  public Writer Write<T>(T value) where T : class, IInterface, new()
  {
    // Do something with value
    return this;
  }
}

class Reader
{
  public Reader Read(out bool value)
  {
    // Retrieve value
    return this;
  }
  public Reader Read(out double value)
  {
    // Retrieve value
    return this;
  }
  public Reader Read(out int value)
  {
    // Retrieve value
    return this;
  }
  public Reader Read<T>(out T value) where T : class, IInterface, new()
  {
    // value = new T() or null
    return this;
  }
}

Now I want to call Write and Read for multiple variables in a row, one of which is of an enum type. However, that enum type causes difficulties in the method resolving. (Btw: I am used to VB.NET, where Enum types are compatible to Integer parameters.)

enum MyEnum : int
{
  Foo = 0, Bar = 1
}

class CallingClass
{
  public void Call()
  {
    bool b;
    double d;
    int i;
    IInterface o;
    MyEnum e = MyEnum.Foo;

    var w = new Writer();

    // Unintuitive for Write
    w
      .Write(b)
      .Write(d)
      .Write(i)
      .Write(o)
      .Write((int) e);

    // w.Write(e); // resolves to Writer.Write<T>(T)
    // => Compile error: "MyEnum has to be reference type to match T"

    // Even worse for Read, you need a temp variable
    // and can't use fluent code anymore:

    var r = new Reader();
    r
      .Read(out b)
      .Read(out d)
      .Read(out i)
      .Read(out o);
    int tmp;
    r.Read(out tmp);
    e = (MyEnum) tmp;
  }
}

Is there any way I can modify Write/Read, Writer/Reader or MyEnum so that w.Write(e) will automatically resolve to Writer.Write(int) and more importantly r.Read(out e) to Reader.Read(int)?

LWChris
  • 3,320
  • 1
  • 22
  • 39
  • http://stackoverflow.com/questions/79126/create-generic-method-constraining-t-to-an-enum?rq=1 – Daniel A. White Nov 19 '15 at 13:35
  • 4
    this seems to be a maintainable nightmare. – Daniel A. White Nov 19 '15 at 13:35
  • 1
    An output parameter with a `void` return seems like it is an anti-pattern. Is there a reason why you chose this approach over a `GetAsBool`, `GetAsInt`, `GetAsDouble`, ... series of methods with the corresponding return types? – erdomke Nov 19 '15 at 13:39
  • @DanielA.White Declaring the int variable is maintainable if you called the method once. Actually I call them very often, so my methods have a fluent interface, so I cannot declare `v` inline or re-use that helper variable. Regarding linked question: this is not possible, since I cannot create a second overload `SetTo` with a different type restriction. – LWChris Nov 19 '15 at 13:40
  • @erdomke The pattern fell prey to the code stripping, actually the methods have a fluent interface. – LWChris Nov 19 '15 at 13:41
  • What about going for `Get(out Enum value)` – Jakob Olsen Nov 19 '15 at 13:45
  • You missed some `voids` in your update where you return `this`. – SimpleVar Nov 19 '15 at 13:51
  • I think you just gotta `(int)e` my friend. Don't go crazy for such a small thing, there are better things to code! – SimpleVar Nov 19 '15 at 13:54
  • I could live with the setter, but three line getter is kind of driving me nuts. Especially if you need to do this for multiple enums, like in my case for 5 different enums. I don't essentially want 5 helper variables and 5 additional casts for what actually is 5 ints. – LWChris Nov 19 '15 at 13:58
  • Try creating another Get and SetTo method using new constraints as per one of the solutions defined here: http://stackoverflow.com/questions/79126/create-generic-method-constraining-t-to-an-enum – Don Nov 19 '15 at 14:04
  • @Don Thanks, that question was already linked, but I cannot create a second overload with a different type constraint and I need the other method since it works well for all the other objects. – LWChris Nov 19 '15 at 14:07
  • You could make an overload that accepts `MyEnum` and does the dirty conversions for you... But really, you wouldn't even want *two* variables for a single field with a setter and getter, in any real scenario. If you're fighting the language - your design doesn't suit it. – SimpleVar Nov 19 '15 at 14:08
  • Silly me, didn't see that. – Don Nov 19 '15 at 14:23

3 Answers3

1

Little late on the answer but since I was having the same issue, an overload like this should work

public void Foo(int a)
{
    // do something
}

public void Foo(Enum @enum)
{
    Foo(Convert.ToInt32(@enum));
}
cnork
  • 11
  • 3
  • 1
    This looks very promising, I'll try it out. For the most generic setup, I should probably expand the writer for byte and long, and then check for the right conversion method using Enum.GetUnderlyingType. – LWChris Apr 30 '21 at 16:42
0

with the where constraint:

public void Get<T>(out T value) where T : class, IInterface, new()

you are explicitly saying that T has to be a reference type (not a value type, as enums are). Try to delete class constraint.

[edit] you can also try this, avoiding out param:

  public T Get<T>() where T : new()
  {
    return default(T);
  } 

and call it as

c.Get<MyEnum>();

but again, if you add an IInterface constraint, no Enum can satisfy it.

Gian Paolo
  • 4,161
  • 4
  • 16
  • 34
  • I need that constraint, since I want an overload for objects implementing that interface, and I need that interface in the `Get` method. – LWChris Nov 19 '15 at 13:44
  • No, I don't want it to resolve to `Get(T value)` at all. It should instead resolve to `Get(int)` since the enum type is an int. – LWChris Nov 19 '15 at 13:52
  • 3
    @LWChris, enums aren't ints in C#. You need to switch your idiom view here and work with the language; not fight it. – David Arno Nov 19 '15 at 13:54
  • @DavidArno Since VB.NET language treated both equally, I assumed C#.NET would, too. If that's not the case, that's fine, but as C# rookie you can't tell whether it's you doing it wrong or the language being utterly different if your usual code pattern does not compile against a different but closely related programming language. – LWChris Nov 19 '15 at 14:04
0

From the comments to my question and Gian Paolo's answer, it has become clear that - opposed to VB.NET - C# does not support implicit type conversion of enum to int or vice versa, even when using tricks.

Hence, my desired "one-method handles all enum types" solution is impossible to achieve.

If you cannot (project hierarchy) or do not want to add overloads per enum type to the Writer/Reader class itself, you can create extension methods for the enum types.

LWChris
  • 3,320
  • 1
  • 22
  • 39