Enumeration and Array Indexes? - c#

I'm working on this homework project and having trouble understanding the text explaining how to correctly take the accessed value of the enumeration and then apply the string array value to it. Can you please help me understand this? The text we are using is very difficult and poorly written for a beginner to understand, so I'm kind of on my own here. I've got the first parts written, but need some help on the accessing of the enumeration value and assigning, I think I'm close, but don't understand how to properly get and set the values on this.
Write a class, MyCourses, that contains an enumeration of all the courses that you are currently taking. This enum should be nested inside of your class MyCourses. Your class should also have an array field that provides a short description (as a String) of each of your courses. Write an indexer that takes one of your enumerated courses as an index and returns the String description of the course.
namespace Unit_4_Project
{
public class MyCourses
{
// enumeration that contains an enumeration of all the courses that
// student is currently enrolled in
public enum CourseName
{
IT274_01AU,
CS210_06AU
}
// array field that provides short description for each of classes,
// returns string description of the course
private String[] courseDescription =
{"Intermediate C#: Teaches intermediate elements of C# programming and software design",
"Career Development Strategies: Teaches principles for career progression, resume preparation, and overall self anaylsis"};
// indexer that takes one of the enumerated courses as an index
// and returns the String description of the course
public String this[CourseName index]
{
get
{
if (index == 1)
return courseDescription[0];
else
return courseDescription[1];
}
set
{
if (index == 1)
courseDescription[0] = value;
else
courseDescription[1] = value;
}
}
}
}//end public class MyCourses

You're close, you just went a little nutty there at the end. The CourseName is nothing but a number. You can index directly into your courseDescription array ...
courseDescription[(int)index]
and you have it. :)

What you're missing is that enums convert to ints. (In fact, under they covers, they basically are ints.)
And arrays can be indexed by ints.
Try indexing your array with a parameter of with the type of your enum.

Here is my response from CodeGuru:
Enumerations are strongly typed, so you cannot compare it to an int directly. You can however cast the enumeration to an int. So you would have this instead:
if ( ( ( int ) index ) == 1)
return courseDescription[0];
else
return courseDescription[1];

Enums do not implicitly convert to ints. But you can explicitly convert them.
public String this[CourseName index]
{
get { return courseDescription[(int)index]; }
set { courseDescription[(int)index] = value; }
If you are going to use enums this way, you should define the actual numerical value they represent.
public enum CourseName
{
IT274_01AU = 0,
CS210_06AU = 1
}
While the current implementation of enums will work, there is nothing that says it will do so in the future.

The trick here is that Enumerations are integral datatypes at their core. This means you can cast back and forth between Enum and Int32 if you want to do so:
You need to change the "get" section to:
public String this[CourseName index]
{
get {
return courseDescription[(int)index];
}
}
This works since the enum is basically equivalent to:
public enum CourseName
{
IT274_01AU = 0,
CS210_06AU = 1
}

Related

Properly identifying enums with same underlying value

Assume I have this enum defined, where several members have the same underlying value:
enum Number
{
One = 1,
Eins = 1,
Uno = 1
}
According to MSDN documentation:
If multiple enumeration members have the same underlying value and you attempt to retrieve the string representation of an enumeration member's name based on its underlying value, your code should not make any assumptions about which name the method will return.
So for example,
var number = Number.One;
Console.WriteLine(number);
gives me the following output:
Eins
Printing all enum members,
Console.WriteLine($"{Number.One} {Number.Eins} {Number.Uno}");
yields the following output:
Eins Eins Eins
However, taking the nameof of each member,
Console.WriteLine($"{nameof(Number.One)} {nameof(Number.Eins)} {nameof(Number.Uno)}");
gives the following result:
One Eins Uno
So apparently the enum members are separable. Can I take advantage of this separation, i.e. is there any way I can assign a specific Number member to a variable and consistently have that same member returned whenever the variable is accessed?
So apparently the enum members are separable
Well, that's not entirely true... They are only separable at compile time.
You see, nameof is actually an expression evaluated at compile time. It is a constant expression. This can be proved by assigning a nameof expression to a const:
const string a = nameof(Number.One);
It compiles.
Trying to get the string representation of a enum value using string interpolation on the other hand, is evaluated at runtime, so this does not compile:
const string a = $"{Number.One}";
At runtime, the enum cases are not separable, so the answer to:
is there any way I can assign a specific Number member to a variable and consistently have that same member returned whenever the variable is accessed?
is "no".
The only possibility I see to always return an expected enum name is to create a 2nd enum next to your first of the underlying type and with the same values but limit the members to those that you expect (and make sure there are no shared values). Then you can cast from one to the other and use the new enum in your refactored code that relies on specific/expected members.
SomeMethod
Console.WriteLine("{0:G}", (KnownNumber)Number.Eins); // > One
Console.WriteLine("{0:G}", (KnownNumber)Number.Uno); // > One
Console.WriteLine("{0:G}", (KnownNumber)Number.One); // > One
Enums.cs
public enum Number
{
One = 1,
Eins = 1,
Uno = 1
}
public enum KnownNumber
{
One = 1,
Two = 2,
Three = 3
}
Fiddle
I wrote something that should get it work
public static class NumberExtension
{
private static Dictionary<int, string> pointers = new Dictionary<int, string>();
public static unsafe void SetValue(this Number source, string value)
{
if (pointers.ContainsKey((int)&source))
pointers[(int)&source] = value;
else
pointers.Add((int)&source, value);
}
public static unsafe string GetValue(this Number source)
{
if (pointers.ContainsKey((int)&source))
return pointers[(int)&source];
return source.ToString();
}
}
And to use:
Number num = default(Number);
num.SetValue(nameof(Number.Uno));
Console.WriteLine(num.GetValue());
However, it looks like a kind of 'hack' and I do NOT recommend it. It would be better if you look for a better solution.

Convert string into Enum [duplicate]

This question already has answers here:
Enum from string, int, etc
(7 answers)
Closed 8 years ago.
I am working on WCF service and want to return preference key as enum rather than string.
How to make enum of preferencekey column which is string type in best optimized way?
You should use the enum.Parse Method:
MyEnum myEnum = (MyEnum)Enum.Parse(typeof(MyEnum), enumString);
I found the code snippet.
Rohit,
The value of preferenceKey could not easily be converted to an enum as you would expect. The strings could be parsed using Enum.Parse() method however the enum names must be different than what you have in the database. The problems are
Your string starts with a number
Your string contains the - characters
Now that being said you could design a different approach to your naming convetion of an enum as an example (I dont like this example personally but might work).
First define a new attribute called EnumName this attribute will be used to decorate your enums with the name that you expect from the database. Such as
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
public sealed class EnumNameAttribute : Attribute
{
readonly string name;
public EnumNameAttribute(string name)
{
this.name = name;
}
public string Name { get { return this.name; } }
}
The next step will be to define your enums (what I dont like is the names)
public enum Preferences
{
[EnumName("6E-SF-TYPE")]
SIX_E_SF_TYPE = 0,
[EnumName("6E-SF-VALUE")]
SIX_E_SF_VALUE = 1
}
Simple enough, we have our enum with each item decorated with the EnumName attribute. The next step will be to create a method to parse the enum based on the string from the database.
public static class EnumNameParser
{
public static Preferences ParseString(string enumString)
{
var members = typeof(Preferences).GetMembers()
.Where(x => x.GetCustomAttributes(typeof(EnumNameAttribute), false).Length > 0)
.Select(x =>
new
{
Member = x,
Attribute = x.GetCustomAttributes(typeof(EnumNameAttribute), false)[0] as EnumNameAttribute
});
foreach(var item in members)
{
if (item.Attribute.Name.Equals(enumString))
return (Preferences)Enum.Parse(typeof(Preferences), item.Member.Name);
}
throw new Exception("Enum member " + enumString + " was not found.");
}
}
This method simply takes an input stream, evaluates all the EnumNameAttributes and returns the first match (or exception if not found).
Then this can be called such as.
string enumString = "6E-SF-TYPE";
var e = EnumNameParser.ParseString(enumString);
Now if you want to take the enum and get the name for the database you can extend your helper method with
public static string GetEnumName(this Preferences preferences)
{
var memInfo = typeof(Preferences).GetMember(preferences.ToString());
if (memInfo != null && memInfo.Length > 0)
{
object[] attrs = memInfo[0].GetCustomAttributes(typeof(EnumNameAttribute), false);
if (attrs != null && attrs.Length > 0)
return ((EnumNameAttribute)attrs[0]).Name;
}
throw new Exception("No enum name attribute defined");
}
I really would recommend storing the numerical values rather than the text values in the database. If you want the text values in the database too then add a table for it. Regardless, the Enum.Parse and .TryParse methods will convert a String and the .ToObject method will convert either text or numbers.
How to make enum of preferencekey column which is string type in best optimized way
Well i am afraid you cannot use your preference key as enum for 2 reasons.
your preference key is starting with integer values making it an in-valid identifier.
it also contains - which is not allowed either.
However, if you are able to convert your preference key to some valid identifiers then you can do this.
i would recomment using Enum.TryParse for parsing because
TryParse(String, Boolean, TEnum) is identical to the Parse(Type, String, Boolean) method, except that instead of throwing an exception, it returns false if the conversion fails. It eliminates the need for exception handling when parsing the string representation of an enumeration value.
Something like this
string testingString = "Test1";
SomeEnum result;
if (Enum.TryParse(testingString, out result))
{
Console.WriteLine("Success");
}
or if case sensitivity doesn't matter to you. Then you can use the overload like this
if (Enum.TryParse(testingString,true, out result))
Console.WriteLine("Success");
where SomeEnum is
public enum SomeEnum
{
Test1 = 1,
Test2 = 2
}
The simples way to do this would be:
1) create an enum representing all possible preference key values, but add a 'invalid' with value -1.
enum PreferenceKey
{
INVALID = -1,
SIX_E_SF_TYPE = 0,
SIX_E_SF_VALUE = 1,
...
}
2) create a list of strings containing the string representations of all preference key values in the same order as the enum.
private List<string> strings = new List<string> {"6E-SF-TYPE", "6E-SF-VALUE", ...};
3) Lookup the column value in the list of strings and cast the position to the enum.
If the column value cannot be found in the list of strings, IndexOf will return -1, which is the 'invalid' value.
PreferenceKey key = (PreferenceKey) strings.IndexOf(preferenceKeyColumnValue);

Best way to assign property using enum c#

How can I effective extend enum to have more than 2 options.
I am reading events from a file, line-by-line.
I have a constructor
public enum EventType
{ A,D }
public class Event
{
public EventType Type { get; set; }
}
I assigned Type property like this:
Type = tokens[2].Equals("A") ? EventType.A : EventType.D,
where token[2] is the string that holds values like "A".
This works fine when there are only A and D, but I want to have 2 more types; say R and C. When I add them to enum field, how can I get the type? The above is giving compilation errors as if using Type as a variable.
I appreciate your immediate help!
Thanks
There are really only three sensible ways to go about this:
Enum.TryParse
If the tokens will always correspond exactly to your enum members, you can use Enum.TryParse:
EventType type;
if (Enum.TryParse(tokens[2], out type)) {
Type = type;
}
else { /* token does not exist as an enum member */ }
This approach is the simplest, but it's probably slower than the next one and it also has another drawback: the author of the code that provides tokens[2] and the author of the enum must always keep their code in sync.
Use a dictionary
var dict = new Dictionary<string, EventType>
{
{ "A", EventType.A },
{ "D", EventType.D },
// more items here
}
Type = dict[tokens[2]]; // no error checking, please add some
This requires some setup, but it's probably the fastest and it also allows accounting for changes in the input strings and/or enum values.
Use an attribute
Alternatively, you can annotate your enum members with a custom attribute and write a helper method that uses reflection to find the correct member based on the value of this attribute. This solution has its uses but it's the least likely candidate; most of the time you should prefer one of the two alternatives.
You can want to use Enum.Parse to get the matching value:
Type = Enum.Parse(typeof(EventType), tokens[2])
If tokens[2] is not defined in EventType, Enum.Parse throws an exception, so you can use Enum.IsDefined to check if there is an enum value for the string:
Enum.IsDefined(typeof(EventType), tokens[2])
You may use Enum.Parse to parse a string. For error handling you may use Enum.GetNames(typeof(EventType)) and iterate over the returned string array, which contains all possible names of the enum.
var type = (EventType)Enum.Parse(typeof(EventType), tokens[2]);
EventType et;
switch(tokens[2])
{
case "A":
et=EventType.A;
break;
case "B":
et=EventType.B;
break;
case "C":
et=EventType.C;
break;
}
return et;

How can i sort by a string property but not alphabetically

i have an object that has a string property called "Status". I have a collection of these objects and want to order a collection by that field which is a string.
the possible values of Status are:
"Open", "Closed", "Pending" so i can't use alphabetic order. What is the best way to say that "Open" is greater than "Closed" which is greater than "Pending" ?
I know there is an IComparer<> interface but i want to see the most elegant way to define the order of various strings.
How about using an Enum instead of a string?
public enum Status
{
Pending,
Closed,
Open
}
Then Open > Closed > Pending
You can also use Jon Skeet's answer to convert your string to an enum, if you can't change the fact that you're returning string.
I would create a mapping of some form, from the string to some naturally sortable value (e.g. integer).
Then you can use:
var sorted = unsorted.OrderBy(x => ConvertStatusToInt32(x.Status));
The conversion method might use a statically-initialized Dictionary, or a switch, or whatever.
(You might want to consider using an enum, by the way - ideally for your original status. That way you don't need to rely on strings at all.)
I think your problem here is that your trying to force semantics on to the string class. If I were you, I'd create my own status object:
public class Status : IComparable
{
private string statusText_ = string.Empty;
private int priority_ = 0;
public class Status(string text, int priority)
{
statusText_ = text;
priority_ = priority;
}
// accessors ...
public int CompareTo(object o)
{
// add compare logic to compare priorities here.
}
}
You could define the order here:
string[] bestOrder = new string[] { "Open", "Closed", "Pending" };
Then sort by the index of (i.e. IndexOf) the string in question in bestOrder.
Depending on how you are sorting the code will vary.. but a delegate to do x => bestOrder.IndexOf(x) or similar is probably what you want.
If it's a static finite collection of options you could replace the string with an enumeration and sort on the integer value of the enumeration .

Extending an enum via inheritance

I know this rather goes against the idea of enums, but is it possible to extend enums in C#/Java? I mean "extend" in both the sense of adding new values to an enum, but also in the OO sense of inheriting from an existing enum.
I assume it's not possible in Java, as it only got them fairly recently (Java 5?). C# seems more forgiving of people that want to do crazy things, though, so I thought it might be possible some way. Presumably it could be hacked up via reflection (not that you'd every actually use that method)?
I'm not necessarily interested in implementing any given method, it just provoked my curiosity when it occurred to me :-)
The reason you can't extend Enums is because it would lead to problems with polymorphism.
Say you have an enum MyEnum with values A, B, and C , and extend it with value D as MyExtEnum.
Suppose a method expects a myEnum value somewhere, for instance as a parameter. It should be legal to supply a MyExtEnum value, because it's a subtype, but now what are you going to do when it turns out the value is D?
To eliminate this problem, extending enums is illegal
You're going the wrong way: a subclass of an enum would have fewer entries.
In pseudocode, think:
enum Animal { Mosquito, Dog, Cat };
enum Mammal : Animal { Dog, Cat }; // (not valid C#)
Any method that can accept an Animal should be able to accept a Mammal, but not the other way around. Subclassing is for making something more specific, not more general. That's why "object" is the root of the class hierarchy. Likewise, if enums were inheritable, then a hypothetical root of the enum hierarchy would have every possible symbol.
But no, C#/Java don't allow sub-enums, AFAICT, though it would be really useful at times. It's probably because they chose to implement Enums as ints (like C) instead of interned symbols (like Lisp). (Above, what does (Animal)1 represent, and what does (Mammal)1 represent, and are they the same value?)
You could write your own enum-like class (with a different name) that provided this, though. With C# attributes it might even look kind of nice.
When built-in enums aren't enough, you can do it the old fashion way and craft your own. For example, if you wanted to add an additional property, for example, a description field, you could do it as follows:
public class Action {
public string Name {get; private set;}
public string Description {get; private set;}
private Action(string name, string description) {
Name = name;
Description = description;
}
public static Action DoIt = new Action("Do it", "This does things");
public static Action StopIt = new Action("Stop It", "This stops things");
}
You can then treat it like an enum like so:
public void ProcessAction(Action a) {
Console.WriteLine("Performing action: " + a.Name)
if (a == Action.DoIt) {
// ... and so on
}
}
The trick is to make sure that the constructor is private (or protected if you want to inherit), and that your instances are static.
Enums are supposed to represent the enumeration of all possible values, so extending rather does go against the idea.
However, what you can do in Java (and presumably C++0x) is have an interface instead of a enum class. Then put you standard values in an enum that implements the feature. Obviously you don't get to use java.util.EnumSet and the like. This is the approach taken in "more NIO features", which should be in JDK7.
public interface Result {
String name();
String toString();
}
public enum StandardResults implements Result {
TRUE, FALSE
}
public enum WTFResults implements Result {
FILE_NOT_FOUND
}
You can use .NET reflection to retrieve the labels and values from an existing enum at run-time (Enum.GetNames() and Enum.GetValues() are the two specific methods you would use) and then use code injection to create a new one with those elements plus some new ones. This seems somewhat analagous to "inheriting from an existing enum".
I didn't see anyone else mention this but the ordinal value of an enum is important. For example, with grails when you save an enum to the database it uses the ordinal value. If you could somehow extend an enum, what would be the ordinal values of your extensions? If you extended it in multiple places how could you preserve some kind of order to these ordinals? Chaos/instability in the ordinal values would be a bad thing which is probably another reason why the language designers have not touched this.
Another difficulty if you were the language designer, how can you preserve the functionality of the values() method which is supposed to return all of the enum values. What would you invoke this on and how would it gather up all of the values?
Adding enums is a fairly common thing to do if you go back to the source code and edit, any other way (inheritance or reflection, if either is possible) is likely to come back and hit you when you get an upgrade of the library and they have introduced the same enum name or the same enum value - I have seen plenty of lowlevel code where the integer number matches to the binary encoding, where you would run into problems
Ideally code referencing enums should be written as equals only (or switches), and try to be future proof by not expecting the enum set to be const
If you mean extends in the Base class sense, then in Java... no.
But you can extend an enum value to have properties and methods if that's what you mean.
For example, the following uses a Bracket enum:
class Person {
enum Bracket {
Low(0, 12000),
Middle(12000, 60000),
Upper(60000, 100000);
private final int low;
private final int high;
Brackets(int low, int high) {
this.low = low;
this.high = high;
}
public int getLow() {
return low;
}
public int getHigh() {
return high;
}
public boolean isWithin(int value) {
return value >= low && value <= high;
}
public String toString() {
return "Bracket " + low + " to " + high;
}
}
private Bracket bracket;
private String name;
public Person(String name, Bracket bracket) {
this.bracket = bracket;
this.name = name;
}
public String toString() {
return name + " in " + bracket;
}
}
Saw a post regarding this for Java a while back, check out http://www.javaspecialists.eu/archive/Issue161.html .
I would like to be able to add values to C# enumerations which are combinations of existing values. For example (this is what I want to do):
AnchorStyles is defined as
public enum AnchorStyles {
None = 0,
Top = 1,
Bottom = 2,
Left = 4,
Right = 8,
}
and I would like to add an AnchorStyles.BottomRight = Right + Bottom so instead of saying
my_ctrl.Anchor = AnchorStyles.Right | AnchorStyles.Bottom;
I can just say
my_ctrl.Anchor = AnchorStyles.BottomRight;
This doesn't cause any of the problems that have been mentioned above, so it would be nice if it was possible.
A temporary/local workaround, when you just want very local/one time usage:
enum Animals { Dog, Cat }
enum AnimalsExt { Dog = Animals.Dog, Cat= Animals.Cat, MyOther}
// BUT CAST THEM when using:
var xyz = AnimalsExt.Cat;
MethodThatNeedsAnimal( (Animals)xyz );
See all answers at: Enum "Inheritance"
You can't inherit from/extend an enum, you can use attributes to declare a description. If you're looking for an integer value, that's built-in.
Hmmm - as far as I know, this can't be done - enumerations are written at design-time and are used as a convenience to the programmer.
I'm pretty sure that when the code is compiled, the equivalent values will be substituted for the names in your enumeration, thereby removing the concept of an enumeration and (therefore) the ability to extend it.
Some time back even i wanted to do something like this and found that enum extensions would voilate lot of basic concepts... (Not just polymorphisim)
But still u might need to do if the enum is declared in external library and
Remember you should make a special caution when using this enum extensions...
public enum MyEnum { A = 1, B = 2, C = 4 }
public const MyEnum D = (MyEnum)(8);
public const MyEnum E = (MyEnum)(16);
func1{
MyEnum EnumValue = D;
switch (EnumValue){
case D: break;
case E: break;
case MyEnum.A: break;
case MyEnum.B: break;
}
}
As far as java is concerned it is not allowed because adding elements to an enum would effectively create a super class rather than a sub class.
Consider:
enum Person (JOHN SAM}
enum Student extends Person {HARVEY ROSS}
A general use case of Polymorphism would be
Person person = Student.ROSS; //not legal
which is clearly wrong.

Categories