2

I'm bone new to generics in C#, and I'm attempting to create a method that will use generics. I tripped across the where keyword when attempting to create a local variable, so I'm sure that it will be part of the solution.

The reason for this is I have several different enum variables but the method would do the same to each (given a string that is one of the enum's defined values, toggle it on, using the enum like a bit field).

I have most of this together, the part I'm now stuck at is being able to tell the generic method it's ok to allow "|=" as I'm certain any type passed in will support the operator.

I would like to be able to maintain generality, if possible, so could either be an enum or a List and I would execute different code paths depending on the type.

Example of what I'm taking about

enum someType { value1 = 1<<0, value2 = 1<<1, value3 = 1<<2 }; // and so on
// some more enums

private T someMethod<T>(string myIdentifyers) 
    where T: new()
{
    // suppose myIdentifiers is 1 more more of the valid enum options
    // assume that the correct strings and enum combinations will be passed
    T retval = new T();

    while () {
    // assume a loop with a method call that parses off one identifyer at a time
        // if I have to convert the enum to an int first, so be it, but
        // at this point I can't tell it that a cast to int exists
        retval |= (T)System.Enum.Parse( typeof(T), oneIdentifyer, false );
    }

    return retval;
}
Stephen
  • 1,607
  • 2
  • 18
  • 40
  • 2
    The enum `someType` should be marked with the `[Flags]` attribute if your using it as a set of bitflags. – asawyer Feb 29 '12 at 15:45
  • @asawyer Do I simply place [Flags] before each enum declaration? – Stephen Feb 29 '12 at 15:51
  • See Bruno Silva's answer, he marked the enum. – asawyer Feb 29 '12 at 15:54
  • 1
    Also in this particular case, you may want to look at: http://stackoverflow.com/questions/2745320/enum-tryparse-with-flags-attribute -- Basically, flags enum parsing is supported by .net, as comma separated value. So you can just create the string from your `myIdentifyers` and pass it to `Enum.TryParse()` – edeboursetty Feb 29 '12 at 16:05

4 Answers4

3

I would try something like this (pseudocode):

[Flags]
enum someType { value1 = 1<<0, value2 = 1<<1, value3 = 1<<2 }; // and so on
// some more enums

private T someMethod<T>(string myIdentifyers) 
    where T: struct, new()
{
           // check if enum
    if (typeof(T).BaseType != typeof(Enum)) // we should probably check for the flags attribute too
            throw new Exception();

    // suppose myIdentifiers is 1 more more of the valid enum options
    // assume that the correct strings and enum combinations will be passed
    int retval = 0;

    while () {
    // assume a loop with a method call that parses off one identifyer at a time
        // if I have to convert the enum to an int first, so be it, but
        // at this point I can't tell it that a cast to int exists
        retval |= (int) (object) System.Enum.Parse( typeof(T), oneIdentifyer, false );
    }

    return (T) (object) retval;
}
Bruno Silva
  • 3,077
  • 18
  • 20
  • So far this is working ... subject to my breaking it again :-) For several enums, do I place [Flags] before each, or is the presence of it at the beginning of the list of declarations sufficient? – Stephen Feb 29 '12 at 16:15
  • 1
    You should place it before each enum declaration. – Bruno Silva Feb 29 '12 at 16:21
  • Thank you, this is a great help. – Stephen Feb 29 '12 at 16:27
  • 1
    One (possibly obvious) caveat is that this will fail at run-time if you specify a different underlying type for your enum, e.g. `enum someType : byte`, just like @Ani mentions of their solution. Hopefully that's not a problem, but worth noting. – Weeble Feb 29 '12 at 16:29
  • @Weeble Worth noting, but won't cause a problem for me (today). – Stephen Feb 29 '12 at 16:38
1

In general, there's no good way to invoke operators on a generic type, although there are some kludges and workarounds that can help out in some circumstances.

See this similar question: Generic C# Code and the Plus Operator

In this case, since you know your enums cast to and from int, I think Bruno's method is the way to go.

Community
  • 1
  • 1
Weeble
  • 17,058
  • 3
  • 60
  • 75
1

It's not possible to express enum generic-constraints as of C# 4. Nor is it possible to express operator-constraints.

That said, I think you're looking for a method like this:

public static T AssembleFlagsEnum<T>(IEnumerable<string> names) where T : struct
{
    return (T)(object)names.Aggregate(0, 
       (valSoFar, name) => valSoFar | Convert.ToInt32(Enum.Parse(typeof(T), name)));
}

Note that this doesn't validate that the type is a [Flags] enum. Nor will it work for enums which have underlying-types other than int.

Ani
  • 111,048
  • 26
  • 262
  • 307
0

Unfortunately it's not possible.

You can restrict with the struct constraint to say value type but obviously that includes more than integers. The only thing you could then do is early in the code to check on the actual type.

Supported constraint restrictions are described at http://msdn.microsoft.com/en-us/library/d5x73970.aspx

You can't do operator constraints - see Solution for overloaded operator constraint in .NET generics

Community
  • 1
  • 1
kaj
  • 5,133
  • 2
  • 21
  • 18