Sample Code:
public enum FruitTypeIs
{
Orange,
Mango,
Banana
}
public void WriteFruitType(FruitTypeIs fruitType)
{
string fruitTypeIs = typeof(FruitTypeIs) + "." + fruitType.ToString(); // -> FruitTypeIs.Mango
Console.WriteLine($"{fruitTypeIs}");
}
In the above sample code, I want to print the received enum value alongwith the enum type. For example, if I receive Mango as the value to the parameter FruitTypeIs fruitType then, I want to print the full value FruitTypeIs.Mango. Since new Fruit types could be added to the enum so, I cannot have a if/switch statement.
As a workaround I can use the statement string fruitTypeIs = typeof(FruitTypeIs) + "." + fruitType.ToString();, which is working fine but is there a better way to do this?
I suggest implementing a generic method
// static - we don't need instance (this) here
// generic - T - suits for any Enum, not necessary FruitTypeIs
public static string FullEnumName<T>(T value) where T : Enum =>
$"{typeof(T).Name}.{Enum.GetName(typeof(T), value)}";
usage:
var value = FruitTypeIs.Mango;
...
Console.Write(FullEnumName(value));
You can implement it as an extension method, e.g.
public static class EnumExtensions {
public static string FullEnumName<T>(this T value) where T : Enum =>
$"{value.GetType().Name}.{Enum.GetName(typeof(T), value)}";
}
and then put it
Console.Write(FruitTypeIs.Mango.FullEnumName());
You can try extension, add an extension for Enum
public static class EnumExtension
{
public static string GetFullType(this Enum e) => $"{e.GetType().Name}.{e}";
}
then you can use this in your code
Console.WriteLine(FruitTypeIs.Banana.GetFullType());
Related
I have a class containing string constants and a class containing readonly objects representing a counter object. I have created a custom attribute that tags the string constant with the string representation of it's corresponding counter. Is there a good way to link the string const to the counter object using the attribute?
Here is an example of the string const:
public static class OperatorDiagnosticsConstants
{
[CounterType(CounterType = "ReagentProbe1")]
public const string R1_PROBE_CODE = "SACT-158";
}
Here is the class containing the readonly counter objects:
public class MaintenanceCounterType : CounterTypeEnum
{
public static readonly MaintenanceCounterType ReagentProbe1 = new MaintenanceCounterType(MaintenanceCounterTypeConstants.ReagentProbe1ID);
}
I can think of two solutions but wonder if there is a more elegant way?
First is in the code that uses these two classes, I could have a convert method with a switch statement. Switch on the attribute string to return the MaintenanceCounterType
public MaintenanceCounterType Convert(string attributeStr)
{
switch (attributeStr)
{
case "ReagentProbe1":
return MaintenanceCounterType.ReagentProbe1;
......
}
}
Or I think I could add the same custom attribute CounterType to the MaintenanceCounterType and use reflection to match them up. I guess by checking the equality of the string property of the custom attribute?
Looking for a more elegant solution. Thanks!
Instead of trying to use that approach, you might consider using C# enums, which have functionality in the API for converting between enum constants and strings.
Converting an enum constant to a string (API):
public class ConvertEnumToStringExample {
enum Colors { Red, Green, Blue, Yellow };
public static void Main() {
Console.WriteLine("The 4th value of the Colors Enum is {0}", Enum.GetName(typeof(Colors), 3));
Console.WriteLine("The 4th value of the Colors Enum is {0}", Enum.GetName(typeof(Colors), Colors.Yellow));
}
}
Converting a string to an enum constant (API):
public class ConvertStringToEnumExample {
enum Colors { Red, Green, Blue, Yellow };
public static void Main() {
string colorString = "Yellow";
Colors colorValue = (Colors) Enum.Parse(typeof(Colors), colorString);
// colorValue is now Colors.Yellow
}
}
An immediate drop in improvement would be to use the nameof operator, so that the link survives any refactoring/renaming:
[CounterType(CounterType = nameof(MaintenanceCounterType.ReagentProbe1)]
public const string R1_PROBE_CODE = "SACT-158";
The convert method can also be simplified using reflection, as you suggested:
public MaintenanceCounterType Convert(string attributeStr)
{
return typeof (MaintenanceCounterType).GetField(attributeStr);
}
That being said, my preferred option in these situations is to replace the string constants with a new class:
public static class OperatorDiagnosticsConstant
{
public readonly string Value;
public readonly MaintenanceCounterType CounterType;
private OperatorDiagnosticsConstant(string value, MaintenanceCounterType counterType)
{
Value = value;
CounterType = counterType;
}
public static OperatorDiagnosticsConstant R1_PROBE_CODE = new OperatorDiagnosticsConstant("SACT-158", MaintenanceCounterType.ReagentProbe1);
}
If you want to attempt to maintain backwards compatibility with existing code that calls OperatorDiagnosticsConstants.R1_PROBE_CODE, you can add an implicit string cast operator:
public static class OperatorDiagnosticsConstant
{
...
public override stirng ToString()
{
return Value;
}
public static implicit operator string(OperatorDiagnosticsConstant constant)
{
return constant.ToString();
}
}
I have property
public MyEnumType MyType {get; set;}
where MyEnumType is
public enum MyEnumType
{
One = 1,
Two = 2,
Three = 3,
}
is it possible to localize MyType property without modification of MyEnumType
It is not. It is not meant to. That is not output text, that are in program names.
This is not localization (translation of output), what you would do is translate class names in the source code.
Localizing the output you can do with a usual localiazation framework. Depends on output technology.
You can use extension method to create your own ToString() without changing the enumeration itself.
using System;
namespace ConsoleApplication1 {
public enum MyEnumType {
One = 1,
Two = 2,
Three = 3,
}
public static class Extension {
public static string ToLocalizedString(this MyEnumType type) {
// check System.Threading.Thread.CurrentThread.CurrentCulture
// if you need current culture context
switch (type) {
case MyEnumType.One:
return "Ein";
case MyEnumType.Two:
return "Zwei";
case MyEnumType.Three:
return "Drei";
default:
throw new NotImplementedException();
}
}
}
class Program {
static void Main(string[] args) {
var foo = MyEnumType.One;
Console.Out.WriteLine(foo.ToLocalizedString());
}
}
}
If you need to "localize" "ToString" conversion you can go for a static method of a static class
public static class Localization
{
public static string ToCultureString(this MyEnumType type)
{
return ResourceManager.GetString(type.ToString(), Culture);
}
}
! please also take care of:
Culture statement;
Resource files where you have translation for the cooresponded keys
rce files for cultures you need, where you are using keys defined in your enumeration
further you can use the following code:
var asString = MyObj.MyType.ToCultureString();
I have the following Enum:
public enum ContentKey {
Menu = 0,
Article = 1,
Topic = 2
};
When I use the Enum I have been doing the following:
((int)ContentKey.Topic).ToString("D2")
Is there some way that I could create an extension to the Enum so I didn't have to code the above?
You can use extension methods:
public static class Ext
{
public static string ToFormattedString(this ContentKey key, string format)
{
//do staff
}
}
Usage:
ContentKey.Topic.ToFormattedString("D2")
I have a string representation of an enum.
string val = "namespace_name.enum_name";
I can use this to get type of enum.
Type myType = Type.GetType(val);
Now I see myType.Name = actual_enum_name and other informations, good.
I have tried to obtain the actual enum values using this information and not successful.
I have tried using Enum.Getvalues, however I got stuck in converting the myType, which is System.Type to EnumType, which is what Enum.Getvalues require(?).
I have tried to actually create an Enum object based on the information obtained and got stuck.
How can I get actual fields (list of members) of that enum from here?
That should work as is, no conversion required. Enum.GetValues() takes a Type. The code below works.
namespace enumtest
{
public enum Mine
{
data1,
data2
}
class Program
{
static void Main(string[] args)
{
Type myenum = Type.GetType("enumtest.Mine");
foreach (var curr in Enum.GetValues(myenum))
{
Console.WriteLine(curr.ToString());
}
}
}
}
This allows you to construct instances of an enum value like this:
namespace enumtest
{
public enum Mine
{
data1,
data2
}
class Program
{
static void Main(string[] args)
{
Type myenum = Type.GetType("enumtest.Mine");
// Let's create an instance now
var values = Enum.GetValues(myenum);
var firstValue = values.GetValue(0);
Mine enumInstance = (Mine)Enum.Parse(myenum, firstValue.ToString());
Console.WriteLine("I have an instance of the enum! {0}", enumInstance);
}
}
}
Suppose i have an Enum ContactNumberType then to get values use
string[] names = Enum.GetValues(typeof(ContactNumberType));
because GetValues() method returns an array
Say I have an enum something like:
enum OrderStatus
{
AwaitingAuthorization,
InProduction,
AwaitingDespatch
}
I've also created an extension method on my enum to tidy up the displayed values in the UI, so I have something like:
public static string ToDisplayString(this OrderStatus status)
{
switch (status)
{
case Status.AwaitingAuthorization:
return "Awaiting Authorization";
case Status.InProduction:
return "Item in Production";
... etc
}
}
Inspired by the excellent post here, I want to bind my enums to a SelectList with an extension method:
public static SelectList ToSelectList<TEnum>(this TEnum enumObj)
however, to use the DisplayString values in the UI drop down I'd need to add a constraint along the lines of
: where TEnum has extension ToDisplayString
Obviously none of this is going to work at all with the current approach, unless there's some clever trick I don't know about.
Does anyone have any ideas about how I might be able to implement something like this?
Is there a compelling reason to use an enum here?
When you start jumping through crazy hoops to use enums, it might be time to use a class.
public class OrderStatus
{
OrderStatus(string display) { this.display = display; }
string display;
public override string ToString(){ return display; }
public static readonly OrderStatus AwaitingAuthorization
= new OrderStatus("Awaiting Authorization");
public static readonly OrderStatus InProduction
= new OrderStatus("Item in Production");
public static readonly OrderStatus AwaitingDispatch
= new OrderStatus("Awaiting Dispatch");
}
You consume it the same as an enum:
public void AuthorizeAndSendToProduction(Order order, ProductionQueue queue)
{
if(order.Status != OrderStatus.AwaitingAuthorization)
{
Console.WriteLine("This order is not awaiting authorization!");
return;
}
order.Status = OrderStatus.InProduction;
queue.Enqueue(order);
}
The string representation is built-in, and all you need is ToString().
Of course, you can use the DisplayAttribute to annotate your Enums.
enum OrderStatus
{
[Display(Description="Long Desc", Name="Awaiting Authorization", ShortName="Wait Auth")]
AwaitingAuthorization,
[Display(Description="...", Name="...", ShortName="...")]
InProduction,
[Display(Description="...", Name="...", ShortName="...")]
AwaitingDespatch
}
You can also opt to create an extension method taking any enumeration value and returning its display name based on the attribute set to it to tidy up the displayed values in the UI, as follows:
public static class EnumExtensions
{
public static string ToName(this Enum enumValue)
{
var displayAttribute = enumValue.GetType()
.GetMember(enumValue.ToString())[0]
.GetCustomAttributes(false)
.Select(a => a as DisplayAttribute)
.FirstOrDefault();
return displayAttribute?.Name ?? enumValue.ToString();
}
}
With
public enum Test
{
[Display(Name="AAA")]
a,
b
}
Code:
Console.WriteLine(Test.a.ToName());
Console.WriteLine(Test.b.ToName());
Results
AAA
b
I want to bind my enums to a SelectList with an extension method:
For type safety, I wouldn't use an extension methods, but instead a static class that deals with the Enum type:
Pre C# 7.3 version. Since Enum is not a valid type constraint prior to 7.3 (and it would cause a compile-time exception), you'll end up by considering that enums are value types and they implement some interfaces, in order to restrict the type parameter as close to Enum as possible.
public static class Enums<TEnum> where TEnum : struct, IComparable, IFormattable, IConvertible
{
static Enums()
{
if (!typeof(TEnum).IsEnum)
{
throw new InvalidOperationException();
}
}
}
C# 7.3+ version, with compile time checking... yay!
public static class Enums<TEnum> where TEnum : Enum
{
}
GetValues Method for the class:
public static IEnumerable<TEnum> GetValues(bool includeFirst)
{
var result = ((TEnum[])Enum.GetValues(typeof(TEnum))).ToList();
if (!includeZero)
result = result.Where(r => r != default).ToList();
return result;
}
If you follow Enum Guidelines and include the Default (zero) value, we can ignore it (sometimes we want to display the value like "None Selected" and sometimes we don't "Invalid Selection").
Then we can add another method:
public static IEnumerable<string> GetNames(bool includeFirst)
{
var result = GetValue(includeFirst)
.Select(v => v.ToName())
.ToList();
return result;
}
Instead of using "ToDisplayString", simply override ToString() of your enum. So if an enum overrides it it will take it, otherwise it will take the default ToString behavior (in ToSelectList).
If you just need to use relatively tiny enumerate classes that have no more than an explicit casting operator, ToString and do not take other usability for the special ones about enum on System and its derived namespaces, then the following example could be a solution:
namespace MyNamespace {
public abstract class EnumerateClass<Type, InheritingClass> : IEquatable<InheritingClass>
where Type : IEquatable<Type>
where InheritingClass : EnumerateClass<Type, InheritingClass> {
internal readonly Type Identifier;
protected EnumerateClass (Type identifier) {
this.Identifier = identifier;
}
public bool Equals(InheritingClass obj)
=> this.Identifier.Equals(obj.Identifier);
public static explicit operator Type(EnumerateClass<Type, InheritingClass> obj)
=> obj.Identifier;
}
public sealed class MyNumber : EnumerateClass<int, MyNumber> {
private MyNumber(int identifier) : base(identifier) { }
public static readonly MyNumber None = new Number(0);
public static readonly MyNumber One = new Number(1);
public static readonly MyNumber Two = new Number(2);
...
public override string ToString() {
switch (this.Identifier) {
case 0: return "None";
case 1: return "One";
case 2: return "Two";
...
}
}
}
}
You could do this:
public static string ToOrderStatusDisplayString(this Enum status)
{
switch ((OrderStatus)status)
{
...
}
}
Then restrict TEnum to Enum: where TEnum : System.Enum
Of course, that way you get a bunch of methods on the Enum itself and lose type safety.