purpose of enumeration? - c#

can someone please give me some examples where enumeration is used? i dont understand the concept. i mean both IEnumerable and enum?
have you used enum? please show me sample code

Anytime you have some kind of mapping between magic values and meanings, then you should consider using an enumeration instead. That way you can work with the enumeration constants instead of the magic values directly.
For example you could have something like this:
string getDayOfWeek(int dayOfWeek)
{
if(dayOfWeek == 0)
return "saturday";
else if(...
}
Instead of using an int input parameter you could instead have an enumeration defined:
enum Days {Sat, Sun, Mon, Tue, Wed, Thu, Fri};
string getDayOfWeek(Days dayOfWeek)
{
if(dayOfWeek == Days.Sat)
return "saturday";
else if(...
}
The first variant of the getDayOfWeek function is considered bad for 2 reasons:
1) It's hard to read, and hence harder to maintain and easier to make a mistake in your code
2) If you want to change Sat to now mean 1 you have a lot of code changes to make
You can read more about enumerations here on MSDN.

To elaborate on Berry's post:
enum Title
{
Mr =1,
Mrs,
Miss
}
An ENUM is a user-defined type. With the enumerator above, you can create as many instances of Title as you would like.
Title mine = Title.Mr;
Title sister = Title.Miss;
etc.
An IEnumerable is an Array of enumerable types. Most helpful to me using the foreach statement.
IEnumerable<string> list = new[] {"stringone", "string2", "stringthree"};
foreach (string s in list)
{
Console.WriteLine(s);
}
will produce the following output:
stringone
string2
stringthree

An enumeration is a type that can have multiple values.
Instead of declaring a variable called color, and assigning it the string "blue" or "green"
you can create a enumeration, and define the colors blue,green etc.
This lets the compiler enforce restrictions if your app doesn't support red for example.
Otherwise you would get a runtime bug that would be more difficult to debug, and or a more lengthy error check routine.
edit
As dtb said, in some languages, enumerations are really just integers under the covers, so it is possible to assign numbers to them. If you are using them correctly, you will be doing this, but it is a valid point nonetheless.

An Enum is basically a list of related constants.
e.g
enum Title
{
Mr =1,
Mrs,
Miss,
Sir,
Madame
}
A full example can be found here

The enum keyword declares an enumeration: http://msdn.microsoft.com/en-us/library/sbbt4032(VS.80).aspx
Enums are types which contain a set of defined constants. For example, you may have an enum defined like this:
public enum Months
{
January = 1,
February = 2,
March = 3,
...
December = 12
}
In your code, you may use this like the following:
Months birthMonth = Months.February;
Enums are useful for when you have multiple, discrete values for a variable, and to increase the readability of your code. For example, which of the following has a clearer intent?
File.Open("myFile.txt", 1, 3);
or
File.Open("myFile.txt", FileMode.Create, FileAccess.ReadWrite);

IEnumerable<T> is an interface used to mark classes (usually collections) that have an enumerator; i.e. you can iterate through their elements.
IEnumerator<T> is an interface that contains the methods to iterate through an enumerator; usually it is used to go through a collection's elements one at a time. The foreach language construct is compiler magic to do all the necessary operations to iterate through an IEnumerator for you.
enum is used to define a list of related, named constants

To tie descriptions to strings. For example, in your database you have a an 'Education Status' column which stores 0,1,2,3. They are tied to 'highschool', 'associates', 'bachelor' and 'masters'. In your application you make an enumeration to help keep these values straight.
enum int EducationStatus
{
highschool,
associates,
bachelor,
masters
}
so you can just say
if(yourRecord.EducationStatus == EducationStatus.highschool)
...
instead of 0. Also, this will help keep values uniform instead of always assuming that 0 means highschool, you use highschool and if it changes to 6, you make that change in one place.

Going to assume you mean enum over IEnumerable<T>.
Enumerations are great for grouping a related set of named values in a semi-type safe manner.
My favorite example of a good use of an enum is to replace a boolean parameter.
For example the following code is equivalent but one is significantly more readable than the other
String.Compare(str1,str2,true);
String.Compare(str1,str2,StringComparison.OrdinalIgnoreCase);

Related

Enum.Parse method returns a different enum member than the one passed into it as the parameter

I expect the following call to the Parse method to return the enum member EN_CA but it returns EN instead.
Enum.Parse(LanguageType, "EN_CA", true);
where:
enum LanguageType
{
EN = 0,
EN_CA = 0,
FR = 1
}
It seems like the Parse method just grabs the first member that maps to the value of the parameter that is passed into it.The Parse method seems to be loosing information during the conversion from string to enum member. Changing the order of EN_CA and EN would make the above call to return EN_CA but that is not going to solve the problem since it would cause a similar issue when calling the method for "EN".
Additional context related information: In my code, the LanguageType Enum is represent the index for a dictionary and these indices are used for localizing the language.
Does anyone have any idea of how to map two enum member to the same value while being able to get proper member from Enum.Parse? Do I just need to implement my own version of Enum.Parse which doesn't collapse the members with the same value into one?
An enum member is distinct from other enum members if and only if it has a different value. Effectively the members of the enumeration are named constants, with no real distinction between them other than the value they hold.
In your LanguageType enum you have two labels for the same value, and no way to distinguish them. Try this:
Console.WriteLine("{0} == {1} ? {2}",
LanguageType.EN.ToString(),
LanguageType.EN_CA.ToString(),
LanguageType.EN == LanguageType.EN_CA);
The output is:
EN == EN ? True
The same thing happens when you assign LanguageType.EN_CA to a variable, then examine the variable later to see what it contains. What you get is LanguageType.EN.
The key here is that the value of the member is all-important in most instances, with the position of the member being the tie-breaker during collisions. When two members have the same value the member that is declared first is the one that you will see whenever you do string conversions, including when you examine the value in the IDE.
So in effect you have a value LanguageType.EN_CA that is only an alias to the value LanguageType.EN.
While I can think of a couple of cute uses for this - like parsing incoming data that has multiple representations for the same value - it is really quite a terrible thing to do in most real-world environments, especially if you want to be able to do fully symmetric serialization/deserialization.
Now, as to your localization Dictionary...
It costs very little to store the same class object multiple times in a Dictionary, since class objects are stored by reference. Assuming you have a Localization class, the following code is not particularly inefficient in terms of storage:
enum LanguageType
{
EN, EN_CA, EN_US, EN_GB, EN_AU, FR
}
Dictionary<LanguageType, Localization> localizations = new Dictionary<LanguageType, Localization>();
localizations[LanguageType.EN] = new Localization("EN");
localizations[LanguageType.EN_CA] = localizations[LanguageType.EN];
localizations[LanguageType.EN_US] = localizations[LanguageType.EN];
localizations[LanguageType.EN_GB] = localizations[LanguageType.EN];
localizations[LanguageType.EN_AU] = localizations[LanguageType.EN];
Even if the Localization object contains a huge collection of resources, the above code only ever creates one instance of it. You get distinct values for the LanguageType members, and the Dictionary does the mappings for you.
You defined 0 twice in your enum - this will not work. Each value has to be unique or how else would an enum recognize its values - it is actually stored as integer.
Change it to:
enum LanguageType
{
EN = 0,
EN_CA = 1,
FR = 2
}
EDIT:
As pointed out by Greenish, you can define multiple names for the same value which acts as a sort of an alias. Using both or multiple names return the same value. If you try to get the string value from an integer value, you will get the first value defined for that integer.
In your case, you cannot achieve what you need using enums. You should probably build your own custom class to achieve that.
Enums basically are named integers. And it is possible to assign different names for a single number (as in your example for 0).
Enum.Parse searching for a first correct instance - and here you have a valid name as 0 == 0. So the solution is to change your numbers (or even just get rid of them as they are 0, 1, 2)
enum LanguageType
{
EN,
EN_CA,
FR
}
I thought of a way but it's messy fragile and naff. There again it illustrates the hole you have dug for yourself..
int index = Enum.GetNames(typeof(LanguageType)).indexof("EN_CA")
will give you 1
then something like
switch(index)
{
case 0 : return LanguageType.EN;
case 1 : return LangaugeType.EN_CA;
case 2 : return LanguageType.FR;
default : // throw some useful exception maybe
break
}
will return the member you want.
Horrible isn't it?
Enum.GetValues(typeof(LanguageType)) would return [0,0,1] and using indexof 0 on it is of course 0, which is why Parse is giving you the result it is.
The =0 specifies the representation of the enum's value in the underlying type (int). You've given both EN and EN_CA the same representation, namely 0, so now they've effectively become two labels for the same value.
Enum.Parse returns this value and it'll equal both labels.
The underlying problem is that you're trying to code a hierarchical concept, into a flat enum. For some purposes all english speaking cultures should be treated equal, for other purposes you'd like to distinguish between them.
The solution, I think, is to use the already present mechanisms for localizing your application, in particular CultureInfo should replace your enum and Resources your lookup dictionary.
I was a little surprised that this use of enum is allowed :)
But the MSDN documentation explicitly states it is valid and gives an example of how it can be useful:
enum Color
{
Red,
Green,
Blue,
Max = Blue
}
So here is how I fixed my problem:
I was not able to find a clean fix for the problem by getting Enum.Parse method return what I was expecting it to.(please see the note*)
My fix was to apply GroupBy(LanguageIndex) on the resulting dictionary which had its index duplicated and therefore throwing an exception. Since I wanted EN_CA and EN to have the same value in the enum that gave me what I was looking for without throwing an exception.
I can see that my fix is not an actual answer to the question that I initially asked, ignoring the context; though I though it might still be applicable to other contexts with a similar issue.
note* : I could have implemented my own version of Enum.Parse - Please see this answer for an alternative implementation - but that required me to put smelly hardcoded stuff into my code, so I just gave up on fixing the Parse method.

GetName for enum with duplicate values

If I have duplicate values in a C# enum, saying
enum MyE {
value1 = 1,
value2 = 2,
valued = 1
}
What should be the values of the following strings?
MyE N = (MyE)1;
string V1 = N.ToString();
string V2 = GetName(MyE, 1);
Is it true that V1 and V2 must contain the same values?
What these values should be?
I haven't found anything in MSDN or here concerning such a «dereferencing» of enums with duplicates, point me to a link, please, if I missed that.
Experimentation shows that:
V1 = "value1"
and
V2 = "value1"
However, this isn't guaranteed. The MSDN page on Enum.GetName states:
If multiple enumeration members have the same underlying value, the GetName method guarantees that it will return the name of one of those enumeration members. However, it does not guarantee that it will always return the name of the same enumeration member. As a result, when multiple enumeration members have the same value, your application code should never depend on the method returning a particular member's name.
From the "Remarks" section on the Enum.GetName method documentation (http://msdn.microsoft.com/en-us/library/system.enum.getname.aspx), it says:
If multiple enumeration members have the same underlying value, the GetName method guarantees that it will return the name of one of those enumeration members. However, it does not guarantee that it will always return the name of the same enumeration member. As a result, when multiple enumeration members have the same value, your application code should never depend on the method returning a particular member's name.
I ran a test to see what would happen experimentally, and it always returned the first value defined (in your example, value1), but according to the official documentation above, you cannot rely on that (see comment by #gluk47, indicating different behavior in the wild).
I disagree with other answers statements
... this isn't guaranteed ...
... you cannot rely on that ...
as well as with msdn statement:
... your application code should never depend on the method returning a particular member's name ...
The story
There was an enum in my software
enum Blabla { A = 0, B = 1, C = 2, D = 3 }
at some point A value changes to AA and later AA changes to AAA. To keep backward compatibility I had to do
enum Blabla { A = 0, AA = 0, AAA = 0, B = 1, C = 2, D = 3 }
This allows to deserialize old enum value (made by older versions of software) as AAA.
Then there was a report which prints Blabla setting value. And at some point every customer using new version start telling me what instead of AAA they see AA value. All of them see AA (and no one report seeing A).
What I did? I simply change the order (until result was AAA)
enum Blabla { AAA = 0, A = 0, AA = 0, ...}
and made a test to ensure what Blabla.AAA will be output as AAA. Problem solved?
The proof
Looking at sources of Enum.ToString() (or Enum.GetName()), it uses GetEnumName(), which calls Array.BinarySearch() for sorted array of values to find an index of value.
The result of binary search is deterministic: providing it with the same parameters will return same result.
So:
if you don't change enum, then result will be the same.
it is possible to find result experimentally (or perhaps by understanding how binary search works and how enum will be processed).
there is no easy rule to determine result (e.g. you can't say "it always return first defined value").
it's unlikely what enum format will be changed (e.g. order of definition and order of list of values differs) or Enum.ToString() will be changed, it can happens however, so make sure you have tests for cases where you rely on return value.
Well, because there are no guarantees about the order and obsolete attribute seems to have no impact on Enum methods, I would usually suggest to use a string property for serialization purpose and use custom code to handle obsolete values.
That way, the primary Enum has no duplicate and contains only current values.
Depending on the serialization framework, you might be able to mark the string property as serializable but obsolete and the actual property used in code to be ignored by serialization.
To handle obsolete values in the string property setter, you can either use an [Obsolete] enum or a switch statement. Typically, I would probably use the former if I have a lot of obsolete values to handle and the latter if I have only a few values to handle.
Also it might make sense to put the code in an helper class or an extension method particularly if you load or store that value from a bunch of places.
Although I have not tried it much in production code, I am wondering if it would be better to use a struct instead of an enum to have more control... but I think it need a lot of boilerplate code that cannot easily be made generic.
Whilst this might be a little late to the Party, this may not be the greatest idea, however, the one work around I did find in my case in which I've had to use duplicate enums is to use the following from the question here; Get String Name from Enum in C#
var name = nameof(DeclaredEnum.EnumName);
Resulting in:
EnumName
You can read more Here as to how it actually works.

Is it possible in .NET 3.5 to specify an enum type?

I have a enumerator which map to a bunch of int
example
enum MyEnum {
Open = 1,
Closed = 2,
Exit = 4
}
I find though that when I want to assign this to an integer, I have to cast it first.
int myEnumNumber = **(int)** MyEnum.Open;
Is it possible to specify the type of an enum so that it is implicit that there is a integer assigned to any value within the enum? That way, I do not need to keep casting it to an int if I want to use it
thanks
No, this is on purpose - enums have an underlying data type, but they are not considered to be identical, because this possibly creates lots of error possibilities that this way are simple to catch.
For example you say so much about having to cast the num all the time - I can not remember when I did do a cast of an enum last time. And I do a LOT of C# programming.
enum MyEnum : int
{
Open = 1,
Closed = 2,
Exit = 4
}
This is also mentioned here.
However, this does not allow you to avoid casting, this allows it to be used with types other than Int32 (which is the default enum type).
In short, yes, you can specify a type but no, you still have to cast it.
There are a few good reasons and probably a lot of bad ones for converting enum values to ints, I'll assume you have a good reason ;).
If you are doing a lot of int casting an extension method might be helpful, here is a quicky extension method:
public static int EnumCast(this Enum theEnum)
{
return (int)((IConvertible)theEnum);
}
And an example of usage in a test:
[Test]
public void EnumCastTest()
{
Assert.That(MyEnum.Exit.EnumCast(), Is.EqualTo(4));
}
You can specify a different underlying type using:
enum : byte MyEnum { ... }
But this does not remove the need to cast to byte (if you really want to). Enums in C# allow you to normally just forget about the underlying type unless your applciation requires it.
Do you really need the underlying integer? It is possible to actually store a string representation of an enumeration value in a database and then recreate the enumeration value from the string at a later point, see this question.
MSDN gives a good tutorial on the do's and don't of enums.

Cannot convert type 'System.Enum' to int

(OK, I'll expose the depths of my ignorance here, please be gentle)
Background
I've got a method which looks (a bit) like this:
public void AddLink(Enum enumVal)
{
string identifier = m_EnumInterpreter(enumVal);
AddLink(identifier);
}
The EnumInterpreter is a Func<Enum, string> that is passed in when the parent class is created.
I'm using Enum because at this level it is 'none of my business'- I don't care which specific enum it is. The calling code just uses a (generated) enum to avoid magic strings.
Question
If the EnumInterpreter sends back an empty string, I'd like to throw an exception with the actual value of enumVal. I thought I would just be able to cast to int, but it the compiler won't have it. What am I doing wrong? (Please don't say 'everything').
System.Enum cannot be directly cast to Integer, but it does explicitly implement IConvertible, meaning you can use the following:
public void AddLink(Enum enumVal)
{
string identifier = m_EnumInterpreter(Convert.ToInt32(enumVal));
AddLink(identifier);
}
Keep in mind that if your Enum is actually using something other than an Integer (such as a float), you'll lose the non-integer data on conversion. Or obviously replace the Convert call with whatever you are converting from (if it's known)
No, you aren't able to cast it to an int because System.Enum is not an enum, it's just the base class for enums.
EDIT:
You can get the value as follows, but it is ugly:
int intVar = (int)enuYourEnum.GetType().GetField("value__").GetValue(objYourEnum);
try this..
m_EnumInterpreter((int) (object) enumVal);
Various things here:
1) the answer of Ryan looks ok, but... I would rather pass the Enum down to the enum interpreter, so that you can do the whole Convert.To... there. If you know that you are using ONLY integer based enums, the Convert.ToInt32() is just fine. Otherwise you may want to add by using either reflection or try/catch other conversions.
2) You may also consider using members of the Enum class, like .GetName(), .GetValue(), etc. since they deal directly with the defined names and values independent of the enum type.
3) technically I would not throw the exception outside the enum interpreter. If that condition is generally true, throw the exception from inside the enum interpreter, so that all uses of the class will benefit of the validation. Or you might end up duplicating code.
4) you seem to have an C++/MFC background judging from your variable naming. You might want to get into C# style naming conventions, it will ease your life when using/reading other peoples code and libraries. Check out MS's StyleCop for a good addin to help with naming.
I don't know whether to include this in my question, or as an answer. The problem is that it isn't THE answer, but it is the answer that works for me.
What I discovered, by chance while trying something else, is that if I just wodge it onto the end of a string, I get what I want:
throw new Exception("EnumInterpreter returns empty string for enumVal=" + enumVal);
//EnumInterpreter returns empty string for enumVal=3720116125
I actually simplified to int in my question, the real data type is uint (in this particular instance). Fortunately, given that I only actually wanted the string, I don't have to worry about that.
I'm not sure which of the three other answers is 'right', so vote away...
For me it was enough to cast to object first, since it's just a compilation error.
public static int AsInt(this Enum #this)
{
return (int)(object)#this;
}
I understand that this is probably not the solution to your exact problem, but I just want to post how I solved this for a particular API I was using.
int result = (int) (ActualEnumType) MethodThatReturnsSystemEnumType( arg1, arg2 );
Hopefully that will be of help to someone. Double cast FTW.
Why not parse the enum to a string and return the actual enum value?
public enum MyEnum { Flower = 1, Tree = 2, Animal = 3 };
string name = MyEnum.Flower.ToString(); // returns "Flower"
I think .ToString() is deprecated and I'm not sure about the new way to do it. I would've thought the actual enum representation would be more useful than the int?

A List of varying types?

Id' like to create a list of data that will be passed from method to method, however I can't use a struct because the data that will be contained in this list will vary depending on the input.
For example
if (x == 1) {
a = 1
b = true
c = 42
d = "hello"
}
if (x == 2) {
a = 2
b = 'g'
c = "sup"
}
I believe my options are thus:
Create an array or List of strings, and cast the data back to what it originally was from strings. This is messy and could lead to bugs of uninterpretable input, though wouldn't be so bad since it'd all be detected at runtime.
Create a struct for each possibility - Is this even good practice?
Somehow use generics. From what I know, while generics are type-safe yet not type-strict, they must be cast to types before being used. Eg if I wanted a List of items here, I'd need to cast them to strings much like would happen with solution 1, making this useless.
My question then, is which of these options is the best? Or is there an alternate option using some sort of generic type I don't know about? The number of possible variables in each case may change, as with their types. I'd like to be able to return a single List or Array to the calling method, so that it may appropriately deal with the result. It will know how to deal with each group of data based on the value of a, as it will be the 'action choice' identifier. I'm also aware that casting them to objects and back each time is very intensive so I'd rather avoid that.
This is probably pretty simple but it has me stumped...
Since you don't know before hand what the list will contain, it looks like a good case for using an ArrayList.
If you want to get back to the values using a key, consider using a Hashtable.
The general principal in .NET is that every type can be cast to System.Object (although it may involve boxing). You can use a method like
void Foo(params object[] parameters) { ... }
Or use the System.Collections.ArrayList class.
The 'problem' is that when you want to use such a value, you will need code like:
if (parameters[i] is string)
{
string s = (string) parameters[i];
...
}
Sorry, this is not a code related answer: there may be a faulty design hidden behind such a construct. Make sure you know what you are doing, otherwise things might fire back.
If not knowing the type of the fields you use beforehand really is required, this calls for an approach that saves the data with their type, like
struct foo {
private object _value;
private string _type;
foo(string myType, object myValue) {
_value = myValue;
_type = myType;
}
}
and then using Generics to handle the business logic.
Basically you need a list typed to Object, and then yes, you're in a mode of casting back.
My question is, structurally, how will you know what indexes are of which type? This sounds like a painful solution at best.
If you really need to store differing types in the list, perhaps try a struct which contains a member of each type, as well as a flag indicating which data type is represented. Then use a generic collection for that struct. Something like (off the top of my head)
struct FooType
{
public string StringValue;
public bool BoolValue;
public int IntValue;
public char CharValue;
public string DataType;
// You'd probably want constructors too
}
Then the generic list:
var values = new List<FooType>();
Now you can add and remove entries in the list using that type, which would then indicate what the core data really is.
I still don't like the answer; it sounds like your design may be trying to do too much and there may be refactoring opportunities, but since I don't see much more of your code or intent, all I can do is answer what you've asked. :)
You could represent the data items using a Dictionary/Hashtable and then add these dictionaries to a List.
You could also add extra type information into the dictionary value if needed.

Categories

Resources