Enum Display Name - Use variable? - c#

Can I do this ? It doesn't seem so.
public enum Options
{
[Display(Name = string.Format("{0} - {1}","Option One", MyClass.myVariable))]
OptionOne=1,
[Display(Name = string.Format("{0} - {1}","Option Two", MyClass.myVariable))]
OptionTwo=2
}
As opposed to this
public enum Options
{
[Display(Name = "Option 1")]
OptionOne=1,
[Display(Name = "Option 2")]
OptionTwo=2
}
If not, how can I make the Display Name for an enum variable ?

Seems like nobody's dealing with:
If not, how can I make the Display Name for an enum variable ?
I can think about some kind of enum map plus extension method which could work like this:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
public enum Foo
{
One = 1,
Two = 2,
}
public static class ExtensionMethods
{
private static readonly Dictionary<Enum, string> s_EnumMap = new Dictionary<Enum, string>
{
{ Foo.One, string.Format("{0} - {1}","Option One", 1) },
{ Foo.Two, string.Format("{0} - {1}","Option Two", 2) }
};
public static String ConvertToString(this Enum eff)
{
return s_EnumMap[eff];
}
}
internal class Program
{
private static void Main(string[] args)
{
Console.WriteLine(Foo.One.ConvertToString());
Console.WriteLine(Foo.Two.ConvertToString());
}
}
}
Integers 1 and 2 can be of course replaced by e.g. static variable, such as MyClass.myVariable. If that is the way you would use this code, then keep in mind that s_EnumMap will store the values that MyClass.myVariable variable had at the time when you first used ExtensionMethods class (i.e. when static fields of MyClass were getting initialized). So modifying the code like this:
public MyClass
{
public static int myVariable = 5;
}
public static class ExtensionMethods
{
private static readonly Dictionary<Enum, string> s_EnumMap = new Dictionary<Enum, string>
{
{ Foo.One, string.Format("{0} - {1}","Option One", MyClass.myVariable) },
{ Foo.Two, string.Format("{0} - {1}","Option Two", 2) }
};
public static String ConvertToString(this Enum eff)
{
return s_EnumMap[eff];
}
}
internal class Program
{
private static void Main(string[] args)
{
Console.WriteLine(Foo.One.ConvertToString());
Console.WriteLine(Foo.Two.ConvertToString());
MyClass.myVariable = 100;
Console.WriteLine(Foo.One.ConvertToString());
Console.WriteLine(Foo.Two.ConvertToString());
}
}
Would result into:
Option One - 5
Option Two - 2
Option One - 5
Option Two - 2
While after commenting out the first two Console.WriteLines, the output would be:
Option One - 100
Option Two - 2
So if you want to dynamicaly react to changes of MyClass.myVariable then you have to implement some logic to update s_EnumMap`, but as long as I don't know more about the goal you are trying to achieve I cannot provide a better answer.

You could write a separate method to get the display name, or even a small class that has an option member and a display name member. I like Michal's idea better, but since I already started writing this I figured I'd throw it out there!
public enum Option
{
OptionOne = 1,
OptionTwo = 2
}
public static string GetOptionDisplayName(Option option)
{
switch (option)
{
case Option.OptionOne:
return string.Format("{0} - {1}", "Option One", MyClass.MyProperty);
case Option.OptionTwo:
return string.Format("{0} - {1}", "Option Two", MyClass.MyProperty);
default:
return option.ToString();
}
}
public class AnotherOption
{
public Option Option { get; set; }
public string DisplayName
{
get { return GetOptionDisplayName(this.Option); }
}
}

What you want cannot be done. The compiler needs to know the value at compile time.

The short answer no. The value within [Display....] can be known at compile time only. E.g. you can define literals, like string or enum value. string.Format() is called at run time. If possible you should call it in you other logic, using you enum. Or use code generating, e.g. with a tt template

Related

Static Dictionary fields used to implement static method

Inside a class I have some properties, two static Dictionaries (private fields) a one static method. The method initializes the properties querying the dictionaries and after a switch returns a string. For some reason the values is always returned as null. Below a simplified version:
using System;
using System.Collections.Generic;
namespace Test
{
class Program
{
public static string first { get; set; }
public static string second { get; set; }
public static string third { get; set; }
private static Dictionary<int, string> Symbols = new Dictionary<int, string>
{
[1] = "A",
[2] = "B",
[3] = "C"
};
private static Dictionary<int, string> Encoding = new Dictionary<int, string>
{
[1] = first,
[2] = second,
[3] = third
};
public static string Encode (int n)
{
string result;
first = Symbols[1];
second = Symbols[2];
third = Symbols[3];
switch (n)
{
case 1:
result = Encoding[1];
break;
case 2:
result = Encoding[2];
break;
case 3:
result = Encoding[3];
break;
default:
result = "EMPTY";
break;
}
return result;
}
static void Main(string[] args)
{
Console.WriteLine(Encode(1));
}
}
}
Encode(4) for example returns, correctly, the string "EMPTY" but from 1 to 3 return null. I'm missing something? Is there any more correct/clean way to do the same thing? Thanks!
The method initializes the properties querying the dictionaries and after a switch returns a string.
Yes, when the method is called, the properties will be initialized. Happens after the Encoding dictionary is populated though. The Encoding dictionary is populated as soon as the type is initialized, and at that point, all the properties will have a value of null.
It's not at all clear to me what you're attempting to achieve here, but I would strongly recommend redesigning the code to avoid this confusion.
(I'd also generally warn against having static mutable properties, and I'd at least suggest using regular .NET naming conventions for them.)

Is it possible to use Enum with Pair Values like dictionary

In c# I'm a little puzzled to understand Enum.
In my specif case I would need store constant value in a Name Value format like>
300 seconds = 5 minutes
At the moment I use this class.
Would be possible to use Enum instead, so I the Enum class would look likes?
Can I store in an Enum a Pair Values?
Could you provide me a sample of code?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace MyWebSite.Models
{
public class Reminders
{
private sortedDictionary<int, string> remindersValue = new SortedDictionary<int, string>();
// We are settign the default values using the Costructor
public Reminders()
{
remindersValue.Add(0, "None");
remindersValue.Add(300, "5 minutes before");
remindersValue.Add(900, "15 minutes before");
}
public SortedDictionary<int, string> GetValues()
{
return remindersValue;
}
}
}
You could use a Tuple<int, int> as dictionary key( at least with .NET >= 4 ).
But since you actually want to store a TimeSpan, use that as key.
private static Dictionary<TimeSpan, string> TimeSpanText = new Dictionary<TimeSpan, string>();
static Reminders()
{
TimeSpanText.Add(TimeSpan.Zero, "None");
TimeSpanText.Add(TimeSpan.FromMinutes( 5 ), "5 minutes before");
TimeSpanText.Add(TimeSpan.FromMinutes( 15 ), "15 minutes before");
TimeSpanText.Add(TimeSpan.FromMinutes( 30 ), "30 minutes before");
TimeSpanText.Add(TimeSpan.FromHours( 1 ), "1 hour before");
// ....
}
public static string DisplayName(TimeSpan ts)
{
string text;
if (TimeSpanText.TryGetValue(ts, out text))
return text;
else
throw new ArgumentException("Invalid Timespan", "ts");
}
You can get the translation in this way:
var quarter = TimeSpan.FromMinutes(15);
string text = TimeSpanText[ quarter ];
You can decorate your enumeration with description attributes and access them later through reflection. For example,
enum ReminderTimes
{
[Description("None")]
None = 0,
[Description("5 minutes before")]
FiveMinutesBefore = 300,
[Description("15 minutes before")]
FifteenMinutesBefore = 900
}
You can get the description by:
public static string GetDescription(this Enum value)
{
FieldInfo field = value.GetType().GetField(value.ToString());
DescriptionAttribute attribute
= Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute))
as DescriptionAttribute;
return attribute == null ? value.ToString() : attribute.Description;
}
See also: http://www.codeproject.com/Articles/13821/Adding-Descriptions-to-your-Enumerations
An enum is actually a named integer type. E.g.
public enum Foo : int
{
SomeValue = 100,
}
which means that you create a Foo enumeration with the type 'int' and some value. I personally always make this explicit to show what is happening, but c# implicitly makes it the 'int' type (32-bit int).
You can use any name for the enum names and can check if it is a valid enum by using Enum.IsDefined (e.g. to check if 300 is a valid enum name).
update
Okay, actually that's not 100% correct to be honest. This update is just to show what's actually happening under the hood. An enum is a value type with fields that act as names. E.g. the above enum is actually:
public struct Foo
{
private int _value;
public static Foo SomeValue { get { return new Foo() { _value = 100 }; } }
}
Notice that the 'int' is the type of the int (in my case explicit). Because it's a value type, it has the same structure as a real integer in memory - which is probably what's being used by the compiler when you're casting.
If you are asking can you store an integer value against an enum then yes you can e.g.
public enum DurationSeconds
{
None = 0,
FiveMinutesBefore = 300,
FifteenMinutesBefore = 900,
ThirtyMinutesBefore = 1800,
OneHourBefore = 3600,
TwoHoursBefore = 7200,
OneDayBefore = 86400,
TwoDaysBefore = 172800
}
Contrary of what I usually do, I'll add another answer, which is IMO the answer to the problem.
You usually want the compiler to do as much checking as you can before actually using run-time checking. That means in this case using Enum's for getting values:
// provides a strong type when using values in memory to make sure you don't enter incorrect values
public enum TimeSpanEnum : int
{
Minutes30 = 30,
Minutes60 = 60,
}
public class Reminders
{
static Reminders()
{
names.Add(TimeSpanEnum.Minutes30, "30 minutes");
names.Add(TimeSpanEnum.Minutes60, "60 minutes");
}
public Reminders(TimeSpanEnum ts)
{
if (!Enum.IsDefined(typeof(TimeSpanEnum), ts))
{
throw new Exception("Incorrect value given for time difference");
}
}
private TimeSpanEnum value;
private static Dictionary<TimeSpanEnum, string> names = new Dictionary<TimeSpanEnum, string>();
public TimeSpan Difference { get { return TimeSpan.FromSeconds((int)value); } }
public string Name { get { return names[value]; } }
}
When creating the program like this, the language helps you in a couple of ways:
You cannot use timespans that aren't defined
It initializes the dictionary only once, to be exact: when the type is constructed
The Enum.IsDefined makes sure you dont use an incorrect int value (e.g. new Reminders((TimeSpanEnum)5) will fail.

Can enums contain strings? [duplicate]

This question already has answers here:
Associating enums with strings in C#
(38 answers)
Closed 9 years ago.
How can I declare an enum that has strings for values?
private enum breakout {
page = "String1",
column = "String2",
pagenames = "String3",
row = "String4"
}
No they cannot. They are limited to numeric values of the underlying enum type.
You can however get similar behavior via a helper method
public static string GetStringVersion(breakout value) {
switch (value) {
case breakout.page: return "String1";
case breakout.column: return "String2";
case breakout.pagenames: return "String3";
case breakout.row: return "String4";
default: return "Bad enum value";
}
}
As others have said, no you cannot.
You can do static classes like so:
internal static class Breakout {
public static readonly string page="String1";
public static readonly string column="String2";
public static readonly string pagenames="String3";
public static readonly string row="String4";
// Or you could initialize in static constructor
static Breakout() {
//row = string.Format("String{0}", 4);
}
}
Or
internal static class Breakout {
public const string page="String1";
public const string column="String2";
public const string pagenames="String3";
public const string row="String4";
}
Using readonly, you can actually assign the value in a static constructor. When using const, it must be a fixed string.
Or assign a DescriptionAttribute to enum values, like here.
No, but you can get the enum's value as a string:
Enum.ToString Method
private enum Breakout {
page,
column,
pagenames,
row
}
Breakout b = Breakout.page;
String s = b.ToString(); // "page"
An enum has integer as underlying type by default, which is also stated here on msdn.
Maybe Enum.GetName()/Enum.GetNames() can be helpful for you.
You can create a dictionary of enums.
public enum OrderType
{
ASC,
DESC
}
public class MyClass
{
private Dictionary<OrderType, string> MyDictionary= new Dictionary<OrderType, string>()
{
{OrderType.ASC, ""},
{OrderType.DESC, ""},
};
}

How should I encapsulate this multi-dimensional enum?

In my application I've got some information that can be one of a small set of values - so I'd like to use an enum to hold it, ensuring valid values through type-safety at compile time:
public enum Something { A1, A2, A3, B1, B2, C1 };
These enums represent multi-dimensional data (they have a letter and a number in the example above), so I'd like to be able to get the value associated with them, e.g.
Something example = Something.A1;
// Now I want to be able to query the values for example:
example.Letter; // I want to get "A"
example.Number; // "1"I want to get 1
I've two possible solutions, neither of them feel very 'clean', so I was interested in which people prefer, and why, or whether anyone has any better ideas.
Option 1:
Create a struct which wraps the enum, and provides properties on the wrapped data, e.g.
public struct SomethingWrapper
{
public Something Value { get; private set; }
public SomethingWrapper(Something val)
{
Value = val;
}
public string Letter
{
get
{
// switch on Value...
}
}
public int Number
{
get
{
// switch on Value...
}
}
}
Option 2:
Leave the enum as it is and create a static Helper class which provides static functions that get the values:
public static class SomethingHelper
{
public static string Letter(Something val)
{
// switch on val parameter
}
public static int Number(Something val)
{
// switch on val parameter
}
}
Which should I choose, and why? Or is there a better solution I've not thought of?
Third option: like the second option, but with extension methods:
public static class SomethingHelper
{
public static string Letter(this Something val)
{
// switch on val parameter
}
public static int Number(this Something val)
{
// switch on val parameter
}
}
Then you can do:
Something x = ...;
string letter = x.Letter();
It's unfortunate that there aren't extension properties, but such is life.
Alternatively, create your own pseudo enum: something like this:
public sealed class Something
{
public static Something A1 = new Something("A", 1);
public static Something A2 = ...;
private Something(string letter, int number)
{
Letter = letter;
Number = number;
}
public string Letter { get; private set; }
public int Number { get; private set; }
}
Why not just use two enums, and maybe define a struct that holds one of each?

C# "Enum" Serialization - Deserialization to Static Instance

Suppose you have the following class:
class Test : ISerializable {
public static Test Instance1 = new Test {
Value1 = "Hello"
,Value2 = 86
};
public static Test Instance2 = new Test {
Value1 = "World"
,Value2 = 26
};
public String Value1 { get; private set; }
public int Value2 { get; private set; }
public void GetObjectData(SerializationInfo info, StreamingContext context) {
//Serialize an indicator of which instance we are - Currently
//I am using the FieldInfo for the static reference.
}
}
I was wondering if it is possible / elegant to deserialize to the static instances of the class?
Since the deserialization routines (I'm using BinaryFormatter, though I'd imagine others would be similar) look for a constructor with the same argument list as GetObjectData(), it seems like this can't be done directly . . Which I would presume means that the most elegant solution would be to actually use an enum, and then provide some sort of translation mechanism for turning an enum value into an instance reference. However, I personally like that the "Enum"'s choices are directly linked with their data.
How might one go about this?
If you need more data with with the Enums, consider using attributes. Example below.
class Name : Attribute
{
public string Text;
public Name(string text)
{
this.Text = text;
}
}
class Description : Attribute
{
public string Text;
public Description(string text)
{
this.Text = text;
}
}
public enum DaysOfWeek
{
[Name("FirstDayOfWeek")]
[Description("This is the first day of 7 days")]
Sunday = 1,
[Name("SecondDayOfWeek")]
[Description("This is the second day of 7 days")]
Monday= 2,
[Name("FirstDayOfWeek")]
[Description("This is the Third day of 7 days")]
Tuesday= 3,
}
Perhaps this will allow you to provide more information with the Enums. You can access the attributes through reflection. If you need an example to retrieve the attribute I can provide that as well but I'm trying to keep this somewhat short.
Use Enum.Parse...Suppose you have the following:
Enum myEnum{
Foo = 1,
Bar = 2,
Baz = 3
};
Then
myEnum myE = myEnum.Foo; /* Default! */
myE = (myEnum)Enum.Parse(myE.GetType(), "Baz");
/* Now, myE should be Baz! */
Console.WriteLine("Enum Selected: {0}", myE.ToString());
The above sample serves to illustrate how to convert a string literal into an enum. I hope this is what you are looking for.

Categories