C# Switch on enums - c#

I have an enum:
public enum Status
{
Incomplete = 1, Complete = 2, Cancelled = 3, Deleted = 4
}
Now on a certain page I wish to list this enum in a checkboxlist. This would be fine except that I want the text of each checkbox to display different text than the enum.
i.e the check boxes should say:
"Not Processed" instead of "Incomplete"
"Processed" instead of "Complete"
"Void" instead of "Cancelled"
Is it possible to put this enum in a foreach and then switch on the status and update the text. Like so:
var statuses = Enum.GetNames(typeof(Status));
foreach (var status in statuses)))
{
switch (status)
{
case Status.Complete.ToString():
status = "Processed";
break; ...etc
}
}
Any ideas would be greatly appreciated.

C# has a language feature that directly addresses your question. Here's an article that gives you the complete details.
The short version: apply extension attribute values to each value:
enum OrderStatus
{
[EnumValueData(Name="New Order")]
NewOrder = 1,
[EnumValueData(Name="In Process")]
Processing = 2,
[EnumValueData(Name="Shipped")]
Shipped = 3
}
Then apply said values to your radio-buttons, listbox or whatever:
public static Dictionary<int, string> GetListItems(Type enumType)
{
if (!enumType.IsEnum)
throw new ApplicationException("GetListItems does not support non-enum types");
Dictionary<int, string> list = new Dictionary<int, string>();
foreach(FieldInfo field in enumType.GetFields(BindingFlags.Static | BindingFlags.GetField | BindingFlags.Public))
{
int value;
string display;
value = (int)field.GetValue(null);
display = Enum.GetName(enumType, value);
foreach(Attribute currAttr in field.GetCustomAttributes(true))
{
EnumValueDataAttribute valueAttribute = currAttr as EnumValueDataAttribute;
if (valueAttribute != null)
display = valueAttribute.Name;
}
list.Add(value, display);
}
return list;
}

You can use the Description attribute in the System.ComponentModel class to assign a text description to each enum value. You can then set the text property by iterating through the enum and getting the Description attribute of each instead of using a switch.
public enum Status
{
[Description("Not Processed")] Incomplete = 1,
[Description("Processed")] Complete = 2,
[Description("Void")] Cancelled = 3,
Deleted = 4
}
You could then use something like the following to get the description of a single enum value (or modify it to return a Dictionary of as Bob showed in his example):
public static string GetEnumDescription ( Object value )
{
try
{
Type objType = value.GetType();
FieldInfo fldInf = objType.GetField( Enum.GetName( objType, value ) );
Object[ ] attributes = fldInf.GetCustomAttributes( false );
if ( attributes.Length > 0 )
{
DescriptionAttribute descAttr = ( DescriptionAttribute )attributes[ 0 ];
return descAttr.Description;
}
else
{
return value.ToString();
}
}
catch
{
return string.Empty;
}
}

You can put your Modification string in an array and then use the enum index to access the array element.

Related

Getting an elements variable name in foreach loop

Is it possible to get an elements variable name in a foreach loop? I have tried nameof(v), which does not seem to work. See below:
//check for blank answer boxes and set flag for validation
foreach (string v in new object[] { answer3, answer4, answer5, answer6b, answer11, answer12, answer13b, answer14c, answer18, answer20 })
{
if (string.IsNullOrWhiteSpace(v))
{
s1.Flag = true;
s1.FlagContent += $"Blank answer box: {nameof(v)}. ";
}
}
For example, if answer3 was null or contained white space, s1.Flag would be set to true and s1.FlagContent would be set to "Blank answer box: answer3".
What you're asking is not possible. And when you consider that a given object may be referenced by any number of variables (all of which could have different names), this idea doesn't even make sense.
The typical way to handle this sort of scenario is to store the answers in a dictionary instead of giving them separate variables. If you absolutely have to have them in separate variables, you can convert them to a dictionary like this:
var dictionary = new Dictionary<string, string>
{
{ "answer1", answer1 },
{ "answer2", answer2 },
{ "answer3", answer3 },
{ "answer4", answer4 },
{ "answer5", answer5 }
};
Then the problem is trivial:
foreach (var item in dictionary)
{
if (string.IsNullOrWhiteSpace(item.Value))
{
s1.Flag = true;
s1.FlagContent += $"Blank answer box: {item.Key}.";
}
}
use a Dictionary:
string answer3 = "bla";
string answer4 = null;
string answer5 = "";
var answers = new Dictionary<string,string>();
answers.Add( nameof(answer3), answer3 );
answers.Add( nameof(answer4), answer4 );
answers.Add( nameof(answer5), answer5 );
foreach( var v in answers )
{
if (string.IsNullOrWhiteSpace(v.Value))
{
s1.Flag = true;
s1.FlagContent += $"Blank answer box: {v.Key}. ";
}
}

Compare enum with integers

Please refer the below enums
public enum Fruit
{
Apple = 1,
Orange = 2,
Banana= 3
}
public enum Color
{
Orange = 1,
Yellow = 2,
Red= 3
}
Now I want to map Fruit with Color.So I implemented
public enum FruitColor
{
1= 3,
2= 1,
3= 2
}
I am getting an syntax error when I implement FruitColor
Identifier Expected
How to resolve this?
There is no point in using an enum to map enum values. I would use a dictionary:
Dictionary<Fruit, Color> FruitToColor = new Dictionary<Fruit, Color>
{ { Fruit.Apple, Color.Red }
, { Fruit.Orange, Color.Orange }
, { Fruit.Banana, Color.Yellow }
};
Color colorOfBanana = FruitToColor[Fruit.Banana]; // yields Color.Yellow
Also just putting it out there because I can, the only advantage is you can encode other data in a custom attribute. However, I'd go with the dictionary or a switch ;)
Given
public enum MyFruit
{
[MyFunky(MyColor.Orange)]
Apple = 1,
[MyFunky(MyColor.Yellow)]
Orange = 2,
[MyFunky(MyColor.Red)]
Banana = 3
}
public enum MyColor
{
Orange = 1,
Yellow = 2,
Red = 3
}
public static class MyExteions
{
public static MyColor GetColor(this MyFruit fruit)
{
var type = fruit.GetType();
var memInfo = type.GetMember(fruit.ToString());
var attributes = memInfo[0].GetCustomAttributes(typeof (MyFunkyAttribute), false);
if (attributes.Length > 0)
return ((MyFunkyAttribute)attributes[0]).Color;
throw new InvalidOperationException("blah");
}
}
public class MyFunkyAttribute : Attribute
{
public MyFunkyAttribute(MyColor color) { Color = color;}
public MyColor Color { get; protected set; }
}
Usage
var someFruit = MyFruit.Apple;
var itsColor = someFruit.GetColor();
Console.WriteLine("Fruit = " + someFruit + ", Color = " + itsColor);
Output
Fruit = Apple, Color = Orange
Full Demo Here
You can't have numbers as enum keys. You could use a dictionary to map the values:
var map = new Dictionary<Fruit, Color>
{
{ Fruit.Apple, Color.Red },
{ Fruit.Orange, Color.Orange },
{ Fruit.Banana, Color.Yellow }
};
To access the mapped values use:
var mappedValue = map[Fruit.Apple];
Alternatively, because you want to map the inverse value (1 to 3 and 3 to 1) you could use casts from an integer, although this could be dangerous because the result could be undefined.
var src = (int) Fruit.Apple; // src = 1;
var tar = 4 - src; // tar = 3;
var mapped = (Color) tar;
More generic example:
function Color Map(Fruit fruit)
{
var src = (int) fruit;
var tar = 4 - src;
var color = (Color) tar;
return color;
}
Member identifiers are not allowed to begin with numeric values, you can however use a method to get the proper values from each enum:
public Fruit GetFruit(this Color c) {
switch ((int)c) {
case 1: return (Fruit)3;
case 2: return (Fruit)2;
case 3: return (Fruit)1;
}
return 0;
}
The reverse of this method would give you the Color from the Fruit. You can call this method via the Color type as a static method:
Fruit myFruit = Color.GetFruit(Color.Orange);

Using C# Enum Flags To Return A Set Of Values Based On Their Bit-Wise OR'ed Values

I understand that you can configure C# enum flags in this way:
[Flags]
public enum MyEnum
{
Unknown = 0,
Type1 = 1,
Type2 = 2,
Type3 = 4,
Type4 = 8,
Type5 = 16
}
And once this is configured, you can represent a set of enumberations like so:
MyEnum enumerationSet = MyEnum.Type1 | MyEnum.Type2
Then you can make checks against this set, such as:
if(enumerationSet.HasFlag(MyEnum.Type1))
{
// Do something
}
Or print their values, like so:
Console.WriteLine("{0}", enumerationSet);
Which would print:
Type1, Type2
However, can I go in reverse order? For instance, if I know that
MyEnum.Type1 | MyEnum.Type2 == 3
Can I then ask MyEnum what set of its value/types would equal 3? Then, I can create an extension method (GetSet) to execute like this:
List<MyEnum> myEnumSetList = MyEnum.GetSet(3)
Returning either a MyEnum set or a set of values, i.e. {1, 2}.
Please advise.
EDIT: I was able to finally figure it out. Posted my answer below.
You can parse it manually with this code:
var res = 3;
var myEnumSetList = res.ToString()
.Split(new[] { ", " }, StringSplitOptions.None)
.Select(v => (MyEnum)Enum.Parse(typeof(MyEnum), v)).ToList();
If you want a list of flags you can use this:
var f = 1 + 4 + 8;
var s = Convert.ToString(f, 2);
var flags =
s.Where(w=> w !='0').Select(
(c, i) =>
(MyEnum)Enum.Parse(typeof(MyEnum),
(int.Parse(c.ToString())*Math.Pow(2, i)).ToString(CultureInfo.InvariantCulture)));
You can just cast the Integer to an Enum and use an & comparison.
example
var num = 1;
var doesExist = (((enumerationSet) & ((MyEnum) num)) != 0);
Then if it exists you can return it in your extension method.
Full Code
var enumList = new List<MyEnum>();
var testNumbers = new List<int>{ 1, 2, 4};
MyEnum enumerationSet = MyEnum.Type1 | MyEnum.Type2;
foreach (var num in testNumbers)
{
var doesExist = (((enumerationSet) & ((MyEnum) num)) != 0);
if (doesExist)
enumList.Add((MyEnum)num);
}
enumList.ForEach(x => Console.WriteLine(x.ToString()));
return enumList;
After some hacking around, I was able to resolve a list of enum values, based on the value of that respective set OR'ed:
protected List<MyEnum> GetEnumSet(int flagNumber)
{
List<MyEnum> resultList= new List<MyEnum>();
foreach (MyEnum value in Enum.GetValues(typeof(MyEnum)))
{
if (((MyEnum)flagNumber).HasFlag(value))
{
resultList.Add(value);
}
}
return resultList;
}
Here, flagNumber is the value of a respective list OR'ed, i.e. MyEnum.Type1 | MyEnum.Type2. Thus, by sending this method the flagNumber, I get the list { MyEnum.Type1, MyEnum.Type2 }

C#: Create a generic method that can return an enum as List<string>

How can I create a generic method that receives an enum type and return its values and names as a list of strings, so I could loop this list and for each iteration I'll be able to print each of the enum values. For example, consider the next pseudo:
enum MyEnum { A=5, B=6, C=8 }
List<string> createEnumStrings(AnyEnum(??))
{
List<string> listResult;
// ??
// a code that will generate:
// listResult[0] = "Value 5 Name A"
// listResult[1] = "Value 6 Name B"
// lsitResult[2] = "Value 8 Name C"
return listResult;
}
Again, note that this method can get any type of an enum
public List<string> GetValues(Type enumType)
{
if(!typeof(Enum).IsAssignableFrom(enumType))
throw new ArgumentException("enumType should describe enum");
var names = Enum.GetNames(enumType).Cast<object>();
var values = Enum.GetValues(enumType).Cast<int>();
return names.Zip(values, (name, value) => string.Format("Value {0} Name {1}", value, name))
.ToList();
}
now if you go with
GetValues(typeof(MyEnum)).ForEach(Console.WriteLine);
will print:
Value 5 Name A
Value 6 Name B
Value 8 Name C
Non-LINQ version:
public List<string> GetValues(Type enumType)
{
if(!typeof(Enum).IsAssignableFrom(enumType))
throw new ArgumentException("enumType should describe enum");
Array names = Enum.GetNames(enumType);
Array values = Enum.GetValues(enumType);
List<string> result = new List<string>(capacity:names.Length);
for (int i = 0; i < names.Length; i++)
{
result.Add(string.Format("Value {0} Name {1}",
(int)values.GetValue(i), names.GetValue(i)));
}
return result;
}

How to apply filter on an enumerable collection?

I have a Datatable "tblFields" with two columns and it's values are as follows.
FieldId FieldValue
------- ----------
0_Name test0
0_Amount 100
1_Name test1
1_Amount 100
2_Name test2
2_Amount 200
3_Name test3
3_Amount 0.00
4_Name test4
4_Amount
The below linq gives me all the rows that does not start with "0_" from the data table. Now I need to apply a filter on this collection to get the only rows where the amount (_Amount) is not equal to 0.00 or empty. Also, it should exclude the _Name row when the _Amount equals 0.00 or empty.
var pairs = from row in tblFields.AsEnumerable()
where !row.Field<string>("FieldId").StartsWith("0_")
select new
{
key = GetId(row.Field<string>("FieldId")),
value = row.Field<string>("FieldValue")
};
I am looking for an output as follows. Is it possible to get this result using linq? Does anyone know any other ways to achieve this? Thanks for any ideas.
1_Name test1
1_Amount 100
2_Name test2
2_Amount 200
This should work (Assuming the Field<T> method returns type T and that it works with numeric types):
var pairs = from row in tblFields.AsEnumerable()
where !row.Field<string>("FieldId").StartsWith("0_")
let value = row.Field<decimal>("FieldValue")
where value != 0.00M
select new
{
Id = row.Field<string>("FieldId"),
Value = value
}
If the Field<T> method does not work with numeric types, then try this:
var pairs = from row in tblFields.AsEnumerable()
where !row.Field<string>("FieldId").StartsWith("0_")
let fieldValueString = row.Field<string>("FieldValue")
let value = String.IsNullOrEmpty(fieldValueString)? 0M : Decimal.Parse(fieldValueString)
where value != 0.00M
select new
{
Id = row.Field<string>("FieldId"),
Value = value
}
Here it should remove both the field ID and Value, but has a slightly different (but still simple) format:
var pair= from row in tblFields.AsEnumerable()
group row by row.Field<string>("FieldId")[0] into idValueGroup
where idValueGroup.Key != "0"
select new
{
IdLine = idValueGroup.ElementAt(0),
ValueLine = idValueGruop.ElementAt(1)
} into linePair
where linePair.ValueLine.Field<decimal>("FieldValue") != 0.00M
select new
{
NameId = linePair.IdLine.Field<string>("FieldId"),
Name = linePair.IdLine.Field<string>("FieldValue"),
ValueId = linePair.ValueLine.Field<string>("FieldId"),
Value = linePair.ValueLine.Field<decimal>("FieldValue")
}
You can do this
var pairs = from row in tblFields.AsEnumerable()
where !row.Field<string>("FieldId").StartsWith("0_")
&& row.Field<string>("FieldValue") != "0.00"
select new
{
key = GetId(row.Field<string>("FieldId")),
value = row.Field<string>("FieldValue")
};
Test Code
public class MyObject
{
public string FieldId { get; set; }
public string FieldValue { get; set; }
}
List<MyObject> list = new List<MyObject> {
new MyObject { FieldId = "0_Name", FieldValue = "test0"},
new MyObject { FieldId = "1_Name", FieldValue = "test1" },
new MyObject { FieldId = "2_Name", FieldValue = "test2" }
};
var pairs = from row in list
where !row.FieldId.StartsWith("0_")
&& row.FieldValue != "0.00")
select new
{
key = row.FieldId,
value = row.FieldValue
};

Categories

Resources