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);
Related
I have this Object:
class Car
{
public int Id { get; set; }
public string Name { get; set; }
public Color Color { get; set; }
}
public enum Color
{
Red = 1,
Blue = 2,
Pink = 3,
Orange = 4,
}
How to create a linq query if I want take objects which have Red and Blue values:
query = query.Where(at => at.Color == Color.Red + Color.Blue);
If I take you at face value, and you want cars to be able to have more than one colour then you need to change your enum to use the Flags attribute.
Like this:
[Flags]
public enum Color
{
Red = 1,
Blue = 2,
Pink = 4,
Orange = 8,
}
Now I can write this code:
var cars = new []
{
new Car() { Name = "Red & Orange", Color = Color.Red | Color.Orange },
new Car() { Name = "Red & Blue", Color = Color.Red | Color.Blue },
};
var query = cars.Where(at => at.Color == (Color.Red | Color.Blue));
That, indeed, returns just the "Red & Blue" car.
However, if you meant or rather than and then you don't need to change your enum and the following is what you need:
query = query.Where(at => at.Color == Color.Red || at.Color == Color.Blue);
Either you can make the query with || or operator
query = query.Where(at => at.Color == Color.Red
|| at.Color == Color.Blue);
Or create an Color array to check whether the value is within the array.
query = query.Where(at => (new Color[] { Color.Red, Color.Blue }).Contains(at.Color));
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 }
I am using the following:
public static SelectList GetOptions<T>(string value = null) where T : struct
{
var values = EnumUtilities.GetSpacedOptions<T>();
var options = new SelectList(values, "Value", "Text", value);
return options;
}
public static IEnumerable<SelectListItem> GetSpacedOptions<T>(bool zeroPad = false) where T : struct
{
var t = typeof(T);
if (!t.IsEnum)
{
throw new ArgumentException("Not an enum type");
}
var numberFormat = zeroPad ? "D2" : "g";
var options = Enum.GetValues(t).Cast<T>()
.Select(x => new SelectListItem
{
Value = ((int) Enum.ToObject(t, x)).ToString(numberFormat),
Text = Regex.Replace(x.ToString(), "([A-Z])", " $1").Trim()
});
return options;
My enum has values:
public enum DefaultStatus {
Release = 0,
Review = 1,
InProgress = 2,
Concept = 3,
None = 99
};
From what I understand the number format should give my values of "01","02" etc but it's giving me ""1","2","3" ..
Is there something obvious I'm doing wrong?
Your GetSpacedOptions has optional parameter zeroPad with default value false.
Use
var values = EnumUtilities.GetSpacedOptions<T>(true);
instead of
var values = EnumUtilities.GetSpacedOptions<T>();
How can I convert an array of enums into a generic array of enums in c#.
To be clear:
Given:
public enum PrimaryColor
{
red = 0,
blue = 1,
yellow = 3
}
public enum SecondaryColor
{
green = 0,
purple = 1,
orange = 2
}
I want to do something like this:
public class MyClass
{
public static void Main()
{
PrimaryColor[] pca = {PrimaryColor.blue, PrimaryColor.yellow};
SecondaryColor[] sca = {SecondaryColor.purple, SecondaryColor.orange};
Enum[] enumArray = pca;
}
}
which leads to a compiler error of:
Cannot implicitly convert type 'PrimaryColor[]' to 'System.Enum[]'
I could use linq or some more iterative process, but I wonder if there is a better cast I could use instead.
You can do it iteratively only
Enum[] enumArray = Array.ConvertAll(pca, item => (Enum)item);
Or (less efficient but Linq!)
Enum[] enumArray = pca.Cast<Enum>().ToArray();
Why you can't simply cast arrays? Because in C# covariance enabled only for arrays of reference types (enums are value types). So, with class Foo you can do:
Foo[] foos = new Foo[10];
object[] array = (object[])foos;
PrimaryColor[] pca = { PrimaryColor.blue, PrimaryColor.yellow };
SecondaryColor[] sca = { SecondaryColor.purple, SecondaryColor.orange };
Enum[] enumArray = pca.Select(q => q as Enum).ToArray();
Or;
for (int i=0; i<pca.Count();i++)
{
enumArray[i] = pca[i];
}
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.