Here is enum;
public enum myEnum{
A= 1,
B= 2,
C= 3,
D= 4,
}
I need a List contains all except D,
this way its works;
List<Enum>{myEnum.A, myEnum.B, myEnum.C}
but of course its extremely ugly. How can directly convert and filter D of this enum
Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().Where(x => x != MyEnum.D).ToList();
You can convert an enum to a list like this:
var enumList = Enum.GetValues(typeof(myEnum)).Cast<myEnum>().ToList();
And to remove myEnum.D, simply call the Remove method:
var enumList = Enum.GetValues(typeof(myEnum)).Cast<myEnum>().ToList().Remove(myEnum.D);
As mentioned in the comments, you could also add only the Enums values, which are not myEnum.D:
var enumList = Enum.GetValues(typeof(myEnum)).Cast<myEnum>().ToList().Where(val => val != myEnum.D);
You can get all the values of an enum by calling Enum.GetValues(type) (https://learn.microsoft.com/en-us/dotnet/api/system.enum.getvalues?view=netframework-4.8)
After getting all the values you can exclude certain values you don't want:
public class Program
{
public static void Main()
{
var allValues = Enum.GetValues(typeof (MyEnum))
.Cast<MyEnum>()
.Except(new[]{MyEnum.D})
.ToArray();
foreach (var val in allValues)
{
Console.WriteLine(val);
}
}
}
public enum MyEnum
{
A,
B,
C,
D
}
This will output:
A
B
C
https://dotnetfiddle.net/hdZmAK
Related
Suppose there is such a record
public record ExampleRecord(int a, int b);
and a method
public int ExampleMethod((int a, int b) t)
{
return t.a + t.b;
}
Is it possible to do something like this to work with record as tuple parameter?
var t = new ExampleRecord(a: 1, b: 2);
ExampleMethod(t);
You can add an implicit conversion to your record type:
public record ExampleRecord(int a, int b)
{
public static implicit operator ValueTuple<int, int> (ExampleRecord record)
{
return (record.a, record.b);
}
}
Use like this:
var t = new ExampleRecord(a: 1, b: 2);
ExampleMethod(t);
You can make extension methods. For example:
public static class ExampleRecordExtensions
{
public static (int, int) ToTuple(this ExampleRecord record)
{
return (record.a, record.b);
}
}
Use like this:
var t = new ExampleRecord(a: 1, b: 2);
ExampleMethod(t.ToTuple());
Alternatively you can use deconstruction. Use like this:
var t = new ExampleRecord(a: 1, b: 2);
ExampleMethod((_, _) = t);
I remind you that record types are classes. These tuples are value types (ValueTuple). Which also means that the tuple you create form the record type will always be a copy of the data.
I have an enum as below:
public enum MyEnum { One, Two, Three}
And I would like to pare some strings to above enum, for example, below strings are going to be parsed as MyEnum.Two:
"Two", "TWO", "Second", "2"
I know I can maintain a mapping function to do this job. However, I just want to find a better way, for example, override Enum.Parse function, or something like that. I have tried to use IConvertable, but it seems not possible. Any idea?
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
public class NameAttribute : Attribute
{
public readonly string[] Names;
public NameAttribute(string name)
{
if (name == null)
{
throw new ArgumentNullException();
}
Names = new[] { name };
}
public NameAttribute(params string[] names)
{
if (names == null || names.Any(x => x == null))
{
throw new ArgumentNullException();
}
Names = names;
}
}
public static class ParseEnum
{
public static TEnum Parse<TEnum>(string value) where TEnum : struct
{
return ParseEnumImpl<TEnum>.Values[value];
}
public static bool TryParse<TEnum>(string value, out TEnum result) where TEnum : struct
{
return ParseEnumImpl<TEnum>.Values.TryGetValue(value, out result);
}
private static class ParseEnumImpl<TEnum> where TEnum : struct
{
public static readonly Dictionary<string, TEnum> Values = new Dictionary<string,TEnum>();
static ParseEnumImpl()
{
var nameAttributes = typeof(TEnum)
.GetFields()
.Select(x => new
{
Value = x,
Names = x.GetCustomAttributes(typeof(NameAttribute), false)
.Cast<NameAttribute>()
});
var degrouped = nameAttributes.SelectMany(
x => x.Names.SelectMany(y => y.Names),
(x, y) => new { Value = x.Value, Name = y });
Values = degrouped.ToDictionary(
x => x.Name,
x => (TEnum)x.Value.GetValue(null));
}
}
}
Then you can (note the double syntax for [Name], multiple [Name] or single [Name] with multiple names):
public enum TestEnum
{
[Name("1")]
[Name("Foo")]
[Name("F")]
[Name("XF", "YF")]
Foo = 1,
[Name("2")]
[Name("Bar")]
[Name("B")]
[Name("XB", "YB")]
Bar = 2
}
and
TestEnum r1 = ParseEnum.Parse<TestEnum>("XF");
TestEnum r2;
bool r3 = ParseEnum.TryParse<TestEnum>("YB", out r2);
Note the use of an inner class (ParseEnumImpl<TEnum>) to cache the TEnum "names".
The best way is just store a Dictionary with mappings:
static Dictionary<string, string> _mappings = new Dictionary<string, string>
{
{ "Two", "Two" },
{ "Second", "Two" },
{ "2", "Two" }
};
Then you call case insensetive version of Enum.Parse(Type, String, Boolean):
String str = "2";
MyEnum number = (MyEnum)Enum.Parse(typeof(MyEnum), _mappings[str], true);
Usually, I prefer simple solution since they are much more understandable than"override Enum.Parse function, or something like that".
But we can do it even more simple by using Dictionary<string, MyEnum>:
static Dictionary<string, MyEnum> _mappings = new Dictionary<string, MyEnum>
{
{ "Two", MyEnum.Two },
{ "Second", MyEnum.Two },
{ "2", MyEnum.Two }
};
Now to get your enum:
MyEnum myEnumb = _mappings[str];
The latter approach also improves performance, since we avoid Enum.Parse invocation.
You are trying to parse two distinct cases:
The input contains the enum's name
The input contains the enum's value
If these two are the only cases in the input, you can simply use the Enum.TryParse Method (String, Boolean, TEnum) to try parsing the text in a case-insensitive manner:
MyEnum output;
if (Enum.TryParse(input,true,out output))
{
// Process succesful value
}
C# 7+ Update: The variable can be declared in the same line now:
if (Enum.TryParse(input,true,out var output))
{
// Process succesful value
}
From the documentation examples you see that TryParse can handle both textual and numeric string inputs.
As for parsing Second, this text has no relation to the enum except in the coder's mind. In this case you would really have to create a mapping and place it somewhere - a dictionary, a custom attribute etc.
In fact, if the data comes from external files, this is an ETL problem instead of a parsing problem. In such cases, the typical solution is to create lookup tables that map inputs to recognized outputs and replace the input with the lookup values before parsing
You can use the nuget package Enums.NET to do a reverse lookup on Description Attribute.
Note there's an overload with an ignoreCase boolean.
public enum PhoneCode
{
[DescriptionAttribute("991")]
Emergency,
[DescriptionAttribute("411")]
Info,
}
PhoneCode code;
EnumsNET.Enums.TryParse("991", out code, EnumsNET.EnumFormat.Description)
While I do like the attributes, I went with a mapping myself and instead, I extended the string base type like this:
public enum Rating
{
High,
Medium,
Low,
Other
};
I then have a static class for my extensions... which holds this code in it:
public static Dictionary<string, Rating> RatingsMap = new Dictionary<string, Rating>()
{
{"Highly recommended", Rating.High},
{"Ok", Rating.Medium},
{"Liked", Rating.Medium},
{"Thumbs down", Rating.Low}
};
public static Rating ToRating(this string me)
{
Rating retval = Rating.Other;
if (EXTENSIONS.RatingsMap.ContainsKey(me))
retval = EXTENSIONS.RatingsMap[me];
return retval;
}
Following #xanatos solution. To obtain the EnumValue you can do next:
public static string GetStringValue(Enum value)
{
string output = null;
Type type = value.GetType();
System.Reflection.FieldInfo fi = type.GetField(value.ToString());
NameAttribute[] attrs = fi.GetCustomAttributes(typeof(NameAttribute), false) as NameAttribute[];
if (attrs.Length > 0)
{
output = attrs[0].Name[0];
}
return output;
}
I am new to C# and I have a question,
I have a a enum something like
public enum
{
[Description("1,2,3")]
123,
[Description("3,4,5")]
345,
[Description("6,7,8 ")]
678,
}
Now I want the enum descriptions to bind to a dropdownlist.. can some one help me..
thanks in advance!
PS: I am sorry if I am not clear..Let me know if I need to be more specific
public static class EnumExtensionMethods
{
public static string GetDescription(this Enum enumValue)
{
object[] attr = enumValue.GetType().GetField(enumValue.ToString())
.GetCustomAttributes(typeof (DescriptionAttribute), false);
return attr.Length > 0
? ((DescriptionAttribute) attr[0]).Description
: enumValue.ToString();
}
public static T ParseEnum<T>(this string stringVal)
{
return (T) Enum.Parse(typeof (T), stringVal);
}
}
//Usage with an ASP.NET DropDownList
foreach(MyEnum value in Enum.GetValues<MyEnum>())
myDDL.Items.Add(New ListItem(value.GetDescription(), value.ToString())
...
var selectedEnumValue = myDDL.SelectedItem.Value.ParseEnum<MyEnum>()
//Usage with a WinForms ComboBox
foreach(MyEnum value in Enum.GetValues<MyEnum>())
myComboBox.Items.Add(new KeyValuePair<string, MyEnum>(value.GetDescription(), value));
myComboBox.DisplayMember = "Key";
myComboBox.ValueMember = "Value";
...
var selectedEnumValue = myComboBox.SelectedItem.Value;
These two extension methods have been invaluable to me for going on 5 years and two different jobs, for exactly your stated need.
This is how you would write it:
public enum Test
{
[Description("1,2,3")]
a = 123,
[Description("3,4,5")]
b = 345,
[Description("6,7,8")]
c = 678
}
//Get attributes from the enum
var items =
typeof(Test).GetEnumNames()
.Select (x => typeof(Test).GetMember(x)[0].GetCustomAttributes(
typeof(DescriptionAttribute), false))
.SelectMany(x =>
x.Select (y => new ListItem(((DescriptionAttribute)y).Description)))
//Add items to ddl
foreach(var item in items)
ddl.Items.Add(item);
You could build a wrapper class that looks for the DescriptionAttribute on each member and displays that. Then bind to the wrapper instance. Something like this:
Get the Enum<T> value Description
This question already has answers here:
How to iterate over values of an Enum having flags?
(18 answers)
Closed 6 years ago.
I know how to loop through enum list of properties, but how would I loop through all "selected" enum properties? For example, if one did Prop1 | Prop2 against public enum Foo { Prop1; Prop2; Prop3 }, how would I achieve this?
This is what I have now:
var values = Enum.GetValues(typeof(FileStatus)).Cast<FileStatus>();
foreach (var value in values)
{
}
It loops through all enum properties, but I'd like to loop only the ones that were "selected".
Update: [Flags] attribute was set.
Update 2: The enum contains a large number of properties, I can't and won't type/hardcode a single property check, instead I want to dynamically loop through each of them and check if my enum instance Bar contains the looped item set.
How about the following:
FileStatus status = FileStatus.New|FileStatus.Amazing;
foreach (FileStatus x in Enum.GetValues(typeof(FileStatus)))
{
if (status.HasFlag(x)) Console.WriteLine("{0} set", x);
}
Or in one fell LINQ swoop:
var flags = Enum.GetValues(typeof(FileStatus))
.Cast<FileStatus>()
.Where(s => status.HasFlag(s));
[Flags]
public enum Foo
{
Prop1 = 1,
Prop2 = 1 << 1,
Prop3 = 1 << 2
}
public static class FooExtensions
{
private static readonly Foo[] values = (Foo[])Enum.GetValues(typeof(Foo));
public static IEnumerable<Foo> GetComponents(this Foo value)
{
return values.Where(v => (v & value) != 0);
}
}
public static class Program
{
public static void Main(string[] args)
{
var foo = Foo.Prop1 | Foo.Prop3;
var components = foo.GetComponents().ToArray();
}
}
Assuming you have this set as a bitmask, then simply "and"-ing the values would determine which are selected.
SomeEnum bitmask = value;
if(bitmask & SomeEnum.Value1 > 0)
// SomeEnum.Value1 was set
FileStatus someValue = ...;
var selectedValues = new List<FileStatus>();
var allValues = Enum.GetValues(typeof(FileStatus)).Cast<FileStatus>();
foreach (var value in allValues )
{
if(someValue & value != 0)//note bitwise AND, not logical AND.
{
selectedValues.Add(value);
//this value is selected. You can stick it in a List or do whatever with it.
}
}
You would need to mark the enum with Flags attribute. To get the values you can use yourObject.EnumProperty.HasFlag method, for example:
class Program
{
[Flags]
public enum Bar { Prop1, Prop2, Prop3 }
public class Foo
{
public Bar SelectedBar { get; set; }
}
static void Main(string[] args)
{
var foo = new Foo();
foo.SelectedBar = Bar.Prop1 | Bar.Prop2;
foo.SelectedBar.HasFlag(Bar.Prop1); //true
foo.SelectedBar.HasFlag(Bar.Prop2); //true
foo.SelectedBar.HasFlag(Bar.Prop3); //false
}
}
I generate dynamic enums that represent integer IDs from my database in a C# ASP.NET solution. I would like two things, although neither may be possible.
1) I want the .ToString() method to give me "345" for example, not the string name of the enum (the int it represents as a string). Every answer to this question seems to be adding
[Description="Blah"]
EnumName = 1
above the declaration and using a GetDescription() method. I have no idea how to do this with the dynamic code that I am using.
2) I'd rather not cast to an int to use it as such, I'd rather (Enum.Name == 5) for example. If this isn't possible I'll cast, but I really don't want to use ((int)Enum.Name)).ToString();
Here's the dynamic code generation:
public static void Main()
{
AppDomain domain = AppDomain.CurrentDomain;
AssemblyName aName = new AssemblyName("DynamicEnums");
AssemblyBuilder ab = domain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Save);
ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");
List<Type> types = new List<Type>();
foreach(ReferenceType rt in GetTypes())
{
EnumBuilder eb = mb.DefineEnum(rt.Name, TypeAttributes.Public, typeof(int));
foreach (Reference r in GetReferences(rt.ID))
{
eb.DefineLiteral(NameFix(r.Name), r.ID);
}
types.Add(eb.CreateType());
}
ab.Save(aName.Name + ".dll");
foreach (Type t in types)
{
foreach (object o in Enum.GetValues(t))
{
Console.WriteLine("{0}.{1} = {2}", t, o, ((int) o));
}
Console.WriteLine();
//Console.ReadKey();
}
Console.WriteLine();
Console.WriteLine("Dynamic Enums Built Successfully.");
}
public static string NameFix(string name)
{
//Strip all non alphanumeric characters
string r = Regex.Replace(name, #"[^\w]", "");
//Enums cannot begin with a number
if (Regex.IsMatch(r, #"^\d"))
r = "N" + r;
return r;
}
There may just be no way to do what I want to do, and I'll be stuck using:
(int)Countries.USA //For int value
((int)Countries.CAN).ToString() //For string representation of int value, ex. "354"
Any ideas?
Could you adapt the type-safe enum pattern to do what you need?
public class MyEnum
{
#region Enum Values
// Pre defined values.
public static readonly MyEnum ValueOne = new MyEnum(0);
public static readonly MyEnum ValueTwo = new MyEnum(1);
// All values in existence.
private static readonly Dictionary<int, MyEnum> existingEnums = new Dictionary<int, MyEnum>{{ValueOne.Value, ValueOne}, {ValueTwo.Value, ValueTwo}};
#endregion
#region Enum Functionality
private readonly int Value;
private MyEnum(int value)
{
Value = value;
}
public static MyEnum GetEnum(int value)
{
// You will probably want to make this thread-safe.
if (!existingEnums.ContainsKey(value)) existingEnums[value] = new MyEnum(value);
return existingEnums[value];
}
public override string ToString()
{
return Value.ToString();
}
#endregion
}
Usage:
private void Foo(MyEnum enumVal)
{
return "Enum Value: " + enumVal; // returns "Enum Value: (integer here)
}
Or:
MyEnum.GetValue(2) == MyEnum.GetValue(4); // false
MyEnum.GetValue(3) == MyEnum.GetValue(3); // true
So you actually want to convert the Enum value to a string not the name? Casting to the Enum's underlying type is the simplest way to get the value out. I think you will struggle to get anything shorter or simpler than ((int)...).
If you don't want to "enumerate" some values, or want to do somthing different you could make your own class of YourEnum which basically has the cast built in, casting when required seems easier and more readable.
Perhaps you actually want some constants.
const string Blah = "345";
EDIT
I had another idea, you could write an extension method for Enum like this,
public static class MyExtentions
{
public static string ValueString(this Enum e)
{
var ut = Enum.GetUnderlyingType(e.GetType());
var castToString = typeOf(MyExtentions).GetMethod("CastToString");
var gcast = cast.MakeGenericMethod(ut);
var gparams = new object[] {e};
return gcast.Invoke(null, gparams).ToString();
}
public static string CastToString<T>(object o)
{
return ((T)o).ToString();
}
}
With this you can call ValueString() on any Enum instance and get a string of the value. It clearly used reflection so the performance won't be amazing but I don't think that matters in your case.
As you're using the Enum class type, how about using the Enum.Format method.
For example:
enum EnumClassA {One, Two, Three, Four};
...
EnumClassA chosenValue = EnumClassA.Three;
Console.WriteLine("Chosen value is {0}", Enum.Format(typeof(EnumClassA), chosenValue, "d"));
This should give an output of:
Chosen value is 2
edit
Another option would be:
EnumClassA.Three.ToString("d"); //Enum.Name.ToString("d")
This also gives a string value of "2".
** edit **
As you're doing comparisons to see if the value exists within your enums how about using Enum.IsDefined(enumType, value) which returns a bool?
Console.WriteLine("Does the enumClassA contain {0} result is {1}", 5, Enum.IsDefined(typeof(enumClassA), 5));
This gives an output of:
Does the enumClassA contain 5 result is False
I realise that the question has been marked as answered, but perhaps using an extension might be useful?
It still allows you to use your generated enums this way.
ps. Take care when calling GetString - don't accidentally call ToString instead!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Reflection.Emit;
namespace ConsoleApplication1
{
public enum YourEnum
{
Apples = 1,
Pears = 2,
}
class Program
{
static void Main(string[] args)
{
foreach (var value in (YourEnum[])Enum.GetValues(typeof(YourEnum)))
{
int v = value.GetValue();
Console.WriteLine("{0} = {1} (int)", value.ToString(), v);
string s = value.GetString();
Console.WriteLine("{0} = {1} (string)", value.ToString(), s);
}
Console.ReadLine();
//Results:
//Apples = 1 (int)
//Apples = 1 (string)
//Pears = 2 (int)
//Pears = 2 (string)
}
}
public static class EnumExtensions
{
public static int GetValue(this Enum value)
{
return Convert.ToInt32(value);
}
public static string GetString(this Enum value)
{
return Convert.ToInt32(value).ToString();
}
}
}