I have the enum structure as follows:
public enum MyEnum
{
One=1,
Two=2,
Three=3
}
Now I want to get a list of MyEnum, i.e., List<MyEnum> that contains all the One, Two Three. Again, I am looking for a one liner that does the thing. I came out with a LINQ query but it was unsatisfactory because it was a bit too long, I think:
Enum.GetNames(typeof(MyEnum))
.Select(exEnum =>
(MyEnum)Enum.Parse(typeof(MyEnum), exEnum))
.ToList();
A better suggestion?
Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>();
I agree with #mquander's code.
However, I would suggest you also cache the list, since it's extremely unlikely to change over the course of the execution of your program. Put it in a static readonly variable in some global location:
public static class MyGlobals
{
public static readonly List<MyEnum> EnumList =
Enum.GetValues(typeof(MyEnum)).Cast<MyEnum>().ToList();
}
Not a one liner (well the implementation isn't, but the method is :P), but perhaps add something like this to a tools/ utility class which will return a generic list:
public static List<T> EnumToList<T>()
{
Type enumType = typeof(T);
// Can't use type constraints on value types, so have to do check like this
if (enumType.BaseType != typeof(Enum))
throw new ArgumentException("T must be of type System.Enum");
return new List<T>(Enum.GetValues(enumType) as IEnumerable<T>);
}
Related
I have written two methods that take a generic enum and return all of its enumerations. The problem is that neither are best practise. So, I suspect that are could be another way that may take a different approach. Anyway, here are the two methods:
One
public static List<T> GetTypedEnumItems<T>( this T selected) where T : struct , IConvertible
{
// must be an enumerated type
var enumType = typeof(T);
var values = Enum.GetValues(enumType).Cast<T>().ToList();
return values;
}
This can be called using the following syntax:
var items = RolebackActionEnum .DeadOff.GetTypedEnumItems();
This cannot be best practise because I shouldn't need to specify an enum value that I just throw away in the extension method.
Two
public static List <T> GetTypedEnumItems<T>( this Type selected) where T : struct , IConvertible
{
// must be an enumerated type
var values = Enum.GetValues(selected).Cast<T>().ToList();
return values;
}
This can be called using the following syntax:
var items = typeof (RolebackActionEnum ).GetTypedEnumItems< RolebackActionEnum>();
This cannot be best practise because I am specifying the Enum twice.
In short, best practise must involve specifying the Enum once as well as not specifying a dummy value for the parameter.
Please help!
Instead of an extension method (which extends an instance because of the this keyword), why not use a simple static method ?
public static class EnumHelper
{
public static IEnumerable<T> GetEnumValues<T>()
where T : struct, IConvertible
{
return Enum.GetValues(typeof(T)).Cast<T>();
}
}
And use it like this :
var items = EnumHelper.GetEnumValues<RolebackActionEnum>();
I have a simple enum, that looks something like the following:
public enum Brand
{
[Description("Friendly Brand Name")]
Brand1,
[Description("Once Again")]
Brand2
} // eo enum Brand
I have an extension method with the following signature:
public static string ToDescription(this Enum self) { /* .. implementation .. */ }
A quick check in LINQPad shows me that:
Brand brand = Brand.Brand1;
brand.ToDescription().Dump();
... all works as intended.
Now comes the fun part. In my code, at this point I want to iterate through the values of an arbituary enum (in this case Brand), and I've only got a System.Type to go on. First, I implemented a quick extension method for Array:
public static IEnumerable<object> AsEnumerable(this Array self)
{
foreach(object o in self)
yield return o;
} // eo AsEnumerable
Knowing that my type is an Enum, I iterate through the values thusly (where type is the actual Brand enum type) (Note: CastTo is just a shorthand extension method for Convert.ChangeType):
foreach (var enumValue in Enum.GetValues(type).AsEnumerable().Select((e) => e.CastTo(type)))
Console.WriteLine(enumValue.ToDescription());
And I get the following runtime error:
'MyNameSpace.Brand' does not contain a definition for 'ToDescription'
Debugging, in the immediate window the type of enumValue is indeed Brand. I am guessing this may have something to do with the way extension methods work - or that I am missing something obvious. Perhaps there's a workaround?
I think your CastTo just changes the type at runtime, why not use the Cast<T> instead?
foreach (var enumValue in Enum.GetValues(type).Cast<Enum>())
Console.WriteLine(enumValue.ToDescription());
The most straightforward approach I can think of is a Dictionary of descriptions:
public static class YourClass
{
public enum Brand { Brand1, Brand2 }
private static Dictionary<Brand, string> Descriptions {get; set;}
static YourClass()
{
YourClass.Descriptions.Add(Brand.Brand1, "Friendly name 1");
YourClass.Descriptions.Add(Brand.Brand2, "Friendly name 2");
}
public static string ToDescription(this Brand brand)
{
// error checking left out
return YourClass.Descriptions[brand];
}
}
This approach will also allow you to expand easily, for instance it's easy to support multiple languages in your "descriptions", or leverage a DAL ...
Extension methods are really just a compile-time syntax sugar for some static method, which you could instead have called directly. So they depend on the statically known type of the variable.
Rather than using your AsEnumerable method, note that Array is already an IEnumerable, System.Linq provides two useful extension methods on IEnumerable to get an IEnumerable<T>: Cast<T> and OfType<T>. These both result in typed enumerables, so you can do:
foreach (var enumValue in Enum.GetValues(type).Cast<Enum>()) {
Console.WriteLine(enumValue.ToDescription());
}
In fact you can also make use of the old implicit cast in foreach:
foreach (Enum enumValue in Enum.GetValues(type)) {
Console.WriteLine(enumValue.ToDescription());
}
Java 7 now has this "diamond syntax" where I can do things like ArrayList<int> = new ArrayList<>();
I'm wondering if C# has a similar syntax that I can take advantage of.
For example, I have this part of a class:
class MyClass
{
public List<double[][]> Prototypes; // each prototype is a array of array of doubles
public MyClass()
{
Prototypes = new List<double[][]>; // I'd rather do List<>, in case I change the representation of a prototype later
}
}
Does anyone know if this is possible, and if so, how I might go about using it?
No, there's nothing quite like the diamond syntax in C#. The closest you could come would be to have something like this:
public static class Lists
{
public static List<T> NewList<T>(List<T> ignored)
{
return new List<T>();
}
}
Then:
public MyClass()
{
ProtoTypes = Lists.NewList(ProtoTypes);
}
That just uses normal generic type inference for methods to get T. Note that the value of the parameter is completely ignored - it's only the compile-time type which is important.
Personally I think this is pretty ugly, and I'd just use the constructor directly. If you change the type of ProtoTypes the compiler will spot the difference, and it won't take long at all to fix it up...
EDIT: Two alternatives to consider:
A similar method, but with an out parameter:
public static class Lists
{
public static void NewList<T>(out List<T> list)
{
list = new List<T>();
}
}
...
Lists.NewList(out ProtoTypes);
The same method, but as an extension method, with the name New:
public static class Lists
{
public static List<T> New<T>(this List<T> list)
{
return new List<T>();
}
}
...
ProtoTypes = ProtoTypes.New();
I prefer the first approach to either of these :)
As Jon Skeet said and Eric Lippert backed up, constructors for generic classes in C# cannot infer their types from their parameters or the type of the variable to which the construction is assigned. The go-to pattern when this type of behavior is useful is usually a static generic factory method, which can infer its own generic type from those of its parameters. Tuple.Create() is an example; give it any list of parameters up to 8, and it will create a strongly-typed generic Tuple with those parameters as the data fields. This doesn't work out well for your case, however.
When the variable will be local, consider doing it the other way around; use variable type inference, via the var keyword:
var Prototypes = new List<double[][]>();
This is how the C# team decided to cut down on typing when instantiating variables. Locals are created - and change - much more often than instance variables, and this approach makes C# code look a little more like JavaScript.
As Jon showed, it's possible to hide the mess, but you'll create more of a mess in the process. Here's another possibility using .NET 3.5/4.0's Expression features:
public static string GetName(this Expression<Func<object>> expr)
{
if (expr.Body.NodeType == ExpressionType.MemberAccess)
return ((MemberExpression) expr.Body).Member.Name;
//most value type lambdas will need this because creating the Expression
//from the lambda adds a conversion step.
if (expr.Body.NodeType == ExpressionType.Convert
&& ((UnaryExpression)expr.Body).Operand.NodeType
== ExpressionType.MemberAccess)
return ((MemberExpression)((UnaryExpression)expr.Body).Operand)
.Member.Name;
throw new ArgumentException(
"Argument 'expr' must be of the form ()=>variableName.");
}
public static void InitializeNew(this object me, params Expression<Func<T>>[] exprs)
where T:new()
{
var myType = me.GetType();
foreach(var expr in exprs)
{
var memberName = expr.GetName()
var myMember = myType.GetMember(memberName,
BindingFlags.Instance|BindingFlags.Public
|BindingFlags.NonPublic|BindingFlags.FlattenHierarchy,
MemberTypes.Field|MemberTypes.Property);
if(myMember == null)
throw new InvalidOperationException(
"Only property or field members are valid as expression parameters");
//it'd be nice to put these under some umbrella of "DataMembers",
//abstracting the GetValue/SetValue methods
if(myMember.MemberType == MemberTypes.Field)
((FieldInfo)myMember).SetValue(me, new T());
else
((PropertyInfo)myMember).SetValue(me, new T());
}
}
//usage
class MyClass
{
public List<double[][]> list1;
public List<double[][]> list2;
public MyOtherObject object1;
public MyClass()
{
this.Initialize(()=>list1, ()=>list2);
this.Initialize(()=>object1); //each call can only have parameters of one type
}
}
The implication is obvious here; it's more trouble than it's worth.
To explain why I seemingly just had this laying around; the above is an adaptation of a method I use to throw ArgumentNullExceptions based on passed parameters, which requires the values to be encapsulated within Expressions in order to retain the names of the actual parameters from the calling method. In that situation, the complexity behind the scenes is reduced since all I need in the main helper is a check for null, and the added complexity saves me a lot more than I spend, by allowing me to one-line my null checks in every method and constructor of the codebase.
I recommend ReSharper as a long-term solution to reducing this typing. When the type of an assignment target is known (as it is for instance fields and properties), and you type = new, ReSharper will pop up a suggestion for the type of the constructor, and auto-fill it for you if you want. If you change either the type or constructor afterward, R# will flag the assignment as inconsistent, and you can tell R# to change whichever one you want to match the other.
If you just want to reduce code verbosity there is an opposite shortand syntax: the var operator
Old: List<int> intList = new List<int>();
New: var intList = new List<int>();
At least you write List only once
I have many Enum types which return from a service and which I want to map to my Enum types.
What I want is to create a mapper class which has all the conversion logic.
I did something like this:
public static class ErrEnumMapper
{
private static Dictionary<FullErrorTypeError, eError> dictionary;
static ErrEnumMapper()
{
var dictionary = new Dictionary<FullErrorTypeError, eError>()
{
{FullErrorTypeError.APP, eError.APPLICATION},
{FullErrorTypeError.INF, eError.INF},
{FullErrorTypeError.NO, eError.NONE},
{FullErrorTypeError.PAX, eError.PASSENGER},
{FullErrorTypeError.SYS, eError.SYSTEM}
};
}
public static eError GetEnum(FullErrorTypeError key)
{
var val = dictionary[key];
if (val != null)
return val;
throw new InvalidOperationException();
}
}
But since I have many other Enums, in this way, I will have to create many static fields (like the "dictionary" fields) and their equivalent method (Like "GetEnum")...is there a better way to do this?
Generic maybe?
Unless the integral values or names are the same for both sets of enums are the same, you can't transpose from one enum value to another without some sort of manual mapping.
Some suggestions:
Reuse the original enums if possible
Keep the integer values of the mapped enum the same as the original enum, so you can just cast from one to another.
Use a convention for the enum names so you can map from one to the other.
Use a custom attribute on each mapped enum value that indicates the correlating original enum value, and have ErrEnumMapper read that attribute. Still manual mapping, just perhaps reorganized.
Of course, in the spirit of KISS, I'd stick with #1, #2, or just deal with the manual mapping.
Maybe I'm not really getting what you mean.. but you can just explicitly cast them if they have the same underlying value:
enum FirstEnum {
ONE,
TWO,
THREE
}
enum SecondEnum {
FOUR,
FIVE,
SIX
}
static void Main(string[] args) {
FirstEnum first = FirstEnum.ONE;
SecondEnum second = (SecondEnum)first;
Console.WriteLine(second); // prints FOUR
}
This allows you to keep your naming convention..
I'm trying to find a way to treat enums generically but I can't find a way to make it work. Say I have several enums declared something like this:
public enum ABC {
One,
Two,
Three
}
public enum DEF {
Four,
Five,
Six
}
and I want to write a method that takes an Enum as a parameter and simply returns name of the enum like this:
public string GetEnumName(Enum anEnum) {
return anEnum.GetType().Name;
}
but if I call it like GetEnumName(DEF); I get the 'is a type being used as a variable' error. Any ideas? thanks
EDIT Sorry judging by the replies I may not have been clear enough. I merely chose GetEnumName as a very simplistic example to illustrate the problem, not how to get the name from a type. Basically I want a method that I can pass ANY enum to and have it act on that enum directly, thanks
Use:
public static string GetTypeName<T>()
{
return typeof(T).Name;
}
Usage:
var result = GetTypeName<DEF>();
Perhaps this will do the trick?
public static class EnumExtensions
{
public static string GetEnumName<T>(this T value) where T : struct
{
var type = typeof(T);
if (!type.IsEnum)
throw new InvalidOperationException(string.Format("{0} is not an enum", type));
return type.GetEnumName(value);
}
}
What you want to write is something like this:
public string GetEnumName<T>() where T : Enum
{
return typeof(T).Name;
}
That is, a generic method with a type parameter constraint.
Unfortunately, there is no way to define such a constraint for enums in C# (nor it is possible to define one for delegates). People usually go for the solution mentioned by #ananthonline.
In fact such constraint is not supported by the C# language but it is supported at the CLR level. Using a tool like Mono.Cecil for example can help you to modify your assembly and apply the constraint on the method after you get it compiled.
Have a look to this article: Constraining generic constraints
You'll find a tool which eases the process of applying non-C#-supported generic type parameter constraints: Cecil constraint patcher
And don't forget there are a lot of useful static methods on the Enum class if you want to work with the names and values of your enum members.
Your problem is that you are passing in the type instead of the System.Type. Change your method to this:
public string GetEnumName(Type enumType) {
return enumType.Name;
}
Just pass the type:
public string GetEnumName(Type enumType)
{
return enumType.Name;
}
And
GetEnumName(typeof(ABC));
At this point if your method does nothing else you could probably just use typeof(ABC).Name instead.
You can't. Generic constraints are not allowed on enum types (including System.Enum). Use Enum.GetName instead.