7

I have the following enum:

public enum LegalShipTypes : byte
{
    Frigate = 1,
    Cruiser = 2,
    Destroyer = 3,
    Submarine = 4,
    AircraftCarrier = 5
}

Is there is a way to get the total value of enum in any way? For instance, this would result in (1 + 2 + 3 + 4 + 5) = 15.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
iTEgg
  • 8,212
  • 20
  • 73
  • 107
  • Be careful. If your primary motivation for using your enums is to give yourself byte constants, consider using constants instead, otherwise you'll just be working against the framework. – Michael Meadows Feb 09 '10 at 17:07
  • im new at this. the reason i chose byte is to have a smaller memory footprint. unless i am wrong. – iTEgg Feb 09 '10 at 17:12
  • It's not the use of a byte that is the problem. I'll post an answer to explain. – Michael Meadows Feb 09 '10 at 17:24
  • 3
    Are you planning on allocating an array of several hundred thousand of these? If not, don't bother to use byte for memory savings. It's only usually a savings if there are lots of them packed in next to each other. Rather than prematurely optimizing this, write your program, analyze its memory usage with a profiler, and *then* do weird things like making enums into bytes if you discover it will help. – Eric Lippert Feb 09 '10 at 17:50
  • 1
    If this is a Battleship clone, I'm not sure that an enum would work. After all, in Battleship, the ship sizes are 2, 3, 3, 4, and 5. – Powerlord Feb 09 '10 at 18:09
  • yeah this is a variation, thats why the enum. – iTEgg Feb 09 '10 at 18:15
  • Bemrose: i think you are right. i should implement it another way cause using enums bans me from using ships of the same size. – iTEgg Feb 09 '10 at 18:45
  • thanks to all their responses as they were mostly correct but my actual needs were understood by Meadows and Bemrose. – iTEgg Feb 09 '10 at 18:48

7 Answers7

11

If you can edit the enum, and you need their sum in many places, you can put it in the enum itself:

public enum LegalShipTypes : byte {
  Frigate = 1,
  Cruiser = 2,
  Destroyer = 3,
  Submarine = 4,
  AircraftCarrier = 5,
  All = Frigate + Cruiser + Destroyer + Submarine + AircraftCarrier
} 

This makes more sense in flags enums though:

[Flags]
public enum LegalShipTypes : byte {
  Frigate = 1,
  Cruiser = 2,
  Destroyer = 4,
  Submarine = 8,
  AircraftCarrier = 16,
  All = Frigate | Cruiser | Destroyer | Submarine | AircraftCarrier
} 

Or you can just use this:

Enum.GetValues(typeof(LegalShipTypes)).Cast<byte>().Sum(x=>x)

Which returns a decimal.

But this is a more general way to do it (works regardless of the underlying type of the enum):

public decimal Sum(Type enumType) {
  return Enum
    .GetValues(enumType)
    .Cast<object>()
    .Sum(x => (decimal)Convert.ChangeType(x, typeof(decimal)));
}
Jordão
  • 55,340
  • 13
  • 112
  • 144
6

I didn't want to type this up as an answer, because it doesn't answer your question directly, but based on your comment in response to my comment to your question, it merits some explanation.

Enums are meant to be very simple type safe representations of state. If you simply use constants, then you can assign the wrong constants to a value. This prevents you from assigning the wrong type of constant to a field. For example, if you have something that expects DayOfWeek, you can't assign a FileAccess value, even though they are both constants of the same underlying type.

DayOfWeek day = FileAccess.Write; // doesn't work

If you need this type safety and you don't need for your enum to exhibit any other type of behavior, then use an enum. If you are concerned with having your enum do other things as well (such as enumeration, mathematical operations, etc) then you should consider using classes. See my example below.

public class LegalShipTypes
{
    private readonly byte _numericValue;
    private readonly string _text;

    private LegalShipTypes(byte numericValue, string text)
    {
        _numericValue = numericValue;
        _text = text;
    }

    public byte Value { get { return _numericValue; } }
    public string Text { get { return _text; } }

    public static IEnumerable<LegalShipTypes> All
    {
        get
        {
            return new[] { Frigate, Cruiser, Destroyer, Submarine, AircraftCarrier };
        }
    }

    public static readonly LegalShipTypes Frigate = new LegalShipTypes(1, "Frigate");
    public static readonly LegalShipTypes Cruiser = new LegalShipTypes(2, "Cruiser");
    public static readonly LegalShipTypes Destroyer = new LegalShipTypes(3, "Destroyer");
    public static readonly LegalShipTypes Submarine = new LegalShipTypes(4, "Submarine");
    public static readonly LegalShipTypes AircraftCarrier = new LegalShipTypes(5, "Aircraft Carrier");
}

Now you can use it in a typesafe way like this:

public class Fleet
{
    private readonly List<LegalShipTypes> _ships;

    public Fleet()
    {
        _ships = new List<LegalShipTypes>();
    }

    public LegalShipTypes Flagship { get; set; }
    public ICollection<LegalShipTypes> Ships { get { return _ships; } }
}

....

var fleet = new Fleet();
fleet.FlagShip = LegalShipTypes.AircraftCarrier;
var iDoNotKnowWhyYouWouldNeedThisBut = LegalShipTypes.All.Sum(ship => ship.Value);
Console.WriteLine("The flagship is a(n) \"{0}\".", fleet.FlagShip.Text);
if (fleet.FlagShip == LegalShipTypes.AircraftCarrier) // this will work because it's a reference comparison
    Console.WriteLine("This should be true");

As you can see, you still have type safety, but much more flexibility. It is more code, but you won't find yourself working against the limitations of enum. To reiterate, enum is meant to be simple. It's supposed to be simple. If your needs are simple, don't hesitate to use it. If your needs are more complex, there's no shame in using good old fashioned object oriented programming to solve your problem.

EDIT

In light of your last comment response that the byte values represents the number of pegs, I would highly recommend you don't use enums to solve your problem. You'd be (ironically) trying to put a round peg in a square hole.

missingfaktor
  • 90,905
  • 62
  • 285
  • 365
Michael Meadows
  • 27,796
  • 4
  • 47
  • 63
  • thank you for taking the time to comment in depth. im at planning and modelling stage at the moment so im not sure which approach to take and i will consider you input if i end up coding it your way. – iTEgg Feb 09 '10 at 18:21
  • i will accept this as the answer as this approach does not limit me to all ships of different sizes. thanks again for your thoughtful response and Bemrose also. – iTEgg Feb 09 '10 at 18:47
  • LegalShipTypes.All.Sum -> is a way to indicate if all ship positions have been hit or not. if yes then winner is declared. – iTEgg Feb 09 '10 at 19:06
  • You might also be able to benefit from impliict operator overlolading... do things like var total = LegalShipTypes.Frigate + LegalShipTypes.Destroyer; – Michael Meadows Feb 09 '10 at 20:42
5

Try the following assuming it's an enum that inherits from System.Int32 (this is the default).

public int Sum(Type enumType) {
  return Enum.GetValues(enumType).Cast<int>().Sum();
}

EDIT didn't notice the OP's question inherits from byte. Here's a version that works with byte

public int Sum(Type enumType) {
  return Enum.GetValues(enumType).Cast<byte>().Select(x => (int)x).Sum();
}
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • It inherits from Byte (see above), but your answer is still correct so +1 as of course you can easy convert your example! – metdos Feb 09 '10 at 17:03
  • The example in the question actually has `byte` as its underlying type, which would require something like `Cast().Sum(b => b)` instead. – LukeH Feb 09 '10 at 17:06
  • @Jared: Your edit doesn't work. There's no overload of `Sum` that extends `IEnumerable` so you need to use one of the overloads that takes a `Func` argument. You can just pass `b => b` as the delegate for an implicit conversion to `Int32`. – LukeH Feb 09 '10 at 17:18
  • @Luke, thans forgot about that. Switched it to hae the additional cast to int – JaredPar Feb 09 '10 at 17:37
  • 1
    @Jared: Sorry, that still doesn't work. The `Cast` method performs a box/unbox for value types rather than a conversion, and you can't unbox to a different type. You'll need to pass a delegate into the `Sum` method to perform the conversion. – LukeH Feb 09 '10 at 17:45
  • @Luke, no sorries needed. I forgot that Cast() is indeed a cast vs. a conversion for value types. I changed it to be a Select style conversion (and actually verified it works this time ;) ) – JaredPar Feb 09 '10 at 17:48
1

See the accepted answer of this similar question:

How do I enumerate an enum?

You could get the values, enumerate through them and just sum the values in the for loop.

Community
  • 1
  • 1
Joel Etherton
  • 37,325
  • 10
  • 89
  • 104
0
 public enum LegalShipTypes : byte
    {
        Frigate = 1,
        Cruiser = 2,
        Destroyer = 3,
        Submarine = 4,
        AircraftCarrier = 5
    }
    class Program
    {
        static void Main()
        {
            byte sum = 0;
            foreach (byte item in Enum.GetValues(typeof(LegalShipTypes)))
            {
                sum += (byte)(object)item;
            }

            Console.WriteLine(sum);
        }
    }
komizo
  • 1,052
  • 14
  • 21
0

A generic version of JaredPar's answer with Luke's correction:

public int Sum<T>(Type enumType) {
    return Enum.GetValues(enumType).Cast<T>().Sum();
}

Call with:

Sum<byte>(typeof(LegalShipTypes));

EDIT: Well, scratch that idea. I suppose:

public int Sum(Type enumType) {
    return Enum.GetValues(enumType).Cast<byte>().Sum();
}

is the answer.

Wesley Wiser
  • 9,491
  • 4
  • 50
  • 69
  • @wawa: Your example doesn't work because there's no overload of `Sum` that extends `IEnumerable`. You need to use one of the overloads that takes a `Func` argument. You can just pass `b => b` as the delegate for an implicit conversion to `Int32`. – LukeH Feb 09 '10 at 17:22
  • 1
    @wawa, this does not compile because there is no generic version of Sum available. Only one for specific types – JaredPar Feb 09 '10 at 17:38
0

If you want to be summing enumerator values, wouldn't you be better off using a flagged enumerator?

Paul Manzotti
  • 5,107
  • 21
  • 27