I currently have a windows phone 8.1 runtime project with enums that use a string value attribute. I want to be able to get an enum value by using the string value attribute, for example use "world" to get the enum value of summer. I am using Windows phone 8.1 runtime so most methods that I have found do not work.
Thanks in advance.
public enum test
{
[StringValue("hello")]
school,
[StringValue("world")]
summer,
[StringValue("fall")]
car
}
public class StringValueAttribute : Attribute
{
private string _value;
public StringValueAttribute(string value)
{
_value = value;
}
public string Value
{
get { return _value; }
}
}
To get to your Attributes you will need to use a method/extension. Folowing this question and answer you can make such a thing:
public class StringValueAttribute : Attribute
{
private string _value;
public StringValueAttribute(string value)
{
_value = value;
}
public string Value
{
get { return _value; }
}
public static string GetStringValue(Enum value)
{
Type type = value.GetType();
FieldInfo fi = type.GetRuntimeField(value.ToString());
return (fi.GetCustomAttributes(typeof(StringValueAttribute), false).FirstOrDefault() as StringValueAttribute).Value;
}
}
Then using this line of code:
string stringTest = StringValueAttribute.GetStringValue(test.summer);
will give a result of "world". (Opposite what you wanted, but hopefuly will give you an idea how to deal with the problem).
Depending on what you want to achieve, you can probably use different methods linke: using Dictionary, struct, properties and probably different ways.
As for parsing Enum values you can achieve it like this:
test testValue = test.summer;
string testString = testValue.ToString();
test EnumValue = (test)Enum.Parse(typeof(test), testString);
EDIT
If you want to get enum from attribute, then this method (probably should be improved) should do the job:
public static T GetFromAttribute<T>(string attributeName)
{
Type type = typeof(T);
return (T)Enum.Parse(typeof(T), type.GetRuntimeFields().FirstOrDefault(
x => (x.CustomAttributes.Count() > 0 && (x.CustomAttributes.FirstOrDefault().ConstructorArguments.FirstOrDefault().Value as string).Equals(attributeName))).Name);
}
Usage:
test EnumTest = StringValueAttribute.GetFromAttribute<test>("world");
Related
I am attaching enum to a picker and onSelect i am binding to the actual value of the enum, not its title.
My enum is as follows:
public enum Reason
{
AnnualLeave = 12,
Emergency = 23,
MaternityLeave = 34
}
My class uses the following to bind the enum title to the picker
public Reason ReasonSelectedOption { get; set; }
public ObservableCollection<Reason> ReasonDisplay
{
get => new ObservableCollection<Reason>(Enum.GetValues(typeof(Reason)).OfType<Reason>().ToList());
}
The actual picker
<Picker
ItemsSource="{Binding ReasonDisplay}"
SelectedItem="{Binding ReasonSelectedOption}"
Title="Please Select"
HorizontalOptions="FillAndExpand" />
Everything works fine except in the actual picker, the options appear as AnnualLeave and MaternityLeave which is what's expected from my code but i want them to appear as Annual Leave and Maternity Leave (with the space inbetween) preserving the selecteditem value
Current case: When user selects AnnualLeave, selectedItem value is 12, if i convert to string the selected value becomes 0.
I am simply asking how to put spaces inbetween the enum options and also preserve the SelectedItem integer value
Here you have to keep in mind the internationalisation.
Even if you don't have localised texts now, you may have to support it in the future. So, keeping that in mind, you won't need simply to "split" the string, but to take a specific text from somewhere (i.e. translate it according to the culture).
You can achieve it with the help of some attributes, extension methods and some clever binding.
Let's say that you want to have a picker with 2 options - what is the property type. The PropertyType is an enum, that looks like this:
public enum PropertyType
{
House,
Apartment
}
Since the built-in Description attribute can't translate texts for us, we can use a custom attribute to assign a specific text to an enum type, like this:
public enum PropertyType
{
[LocalizedDescription(nameof(R.SingleFamilyHouse))]
House,
[LocalizedDescription(nameof(R.ApartmentBuilding))]
Apartment
}
The attribute code looks like this:
public class LocalizedDescriptionAttribute : DescriptionAttribute
{
private readonly ResourceManager resourceManager;
private readonly string resourceKey;
public LocalizedDescriptionAttribute(string resourceKey, Type resourceType = null)
{
this.resourceKey = resourceKey;
if (resourceType == null)
{
resourceType = typeof(R);
}
resourceManager = new ResourceManager(resourceType);
}
public override string Description
{
get
{
string description = resourceManager.GetString(resourceKey);
return string.IsNullOrWhiteSpace(description) ? $"[[{resourceKey}]]" : description;
}
}
}
R is my resx file. I have created a Resources folder and inside it I have 2 resx files - R.resx (for English strings) & R.de.resx (for German translation). If you don't want to have internationalisation now, you can change the implementation to get your strings from another place. But it is considered a good practice to always use a resx file, even if you only have 1 language. You never now what tomorrow may bring.
Here is my structure:
The idea behind LocalizedDescriptionAttribute class is that the built-in Description attribute isn't very useful for our case. So we'll have to take the resource key that we have provided it, translates and to override the Description attribute, which later we will reference.
Now we need to obtain the localised description text with this helper method:
public static class EnumExtensions
{
public static string GetLocalizedDescriptionFromEnumValue(this Enum value)
{
return !(value.GetType()
.GetField(value.ToString())
.GetCustomAttributes(typeof(LocalizedDescriptionAttribute), false)
.SingleOrDefault() is LocalizedDescriptionAttribute attribute) ? value.ToString() : attribute.Description;
}
}
Now, when we create the bindings for the Picker, we won't just use a simple Enum, but a specific PropertyTypeViewModel, which will have 2 properties - the Enum itself and a Name that will be displayed.
public class PropertyTypeViewModel : BaseViewModel
{
private string name;
public string Name
{
get => name;
set => SetValue(ref name, value);
}
private PropertyType type;
public PropertyType Type
{
get => type;
set => SetValue(ref type, value);
}
public PropertyTypeViewModel()
{
}
public PropertyTypeViewModel(PropertyType type)
: this()
{
Type = type;
Name = type.GetLocalizedDescriptionFromEnumValue();
}
}
The important line is the last one - Name = type.GetLocalizedDescriptionFromEnumValue();
The final thing that is left is to set your Picker's ItemsSource to your collection of PropertyTypeViewModels and ItemDisplayBinding to be pointing to the Name property - ItemDisplayBinding="{Binding Name}"
That's it - now you have a Picker with dynamic localised strings.
You could use a converter
public class EnumToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null) return null;
var valueAsString = value.ToString();
valueAsString = valueAsString.SplitCamelCase();
return valueAsString;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
And for the SplitCamelCase I wrote this but I'm sure there are cleaner options:
public static string SplitCamelCase(this string str)
{
string result = "";
for (int i = 0; i < str.Count(); i++)
{
var letter = str[i];
var previousLetter = i != 0 ? str[i - 1] : 'A';
if (i != 0 && char.IsUpper(previousLetter) == false && char.IsUpper(letter)) result = result + " " + letter;
else result = result + letter;
}
return result;
}
Then just used it like so:
<TextBlock Text="{Binding Converter={StaticResource EnumToStringConverter}}"/>
I have a static class with constants. I am looking for options to create a method which takes a dictionary as an argument and enforcing the key to be one of the constants from the static class.Here is my static class with constants.
Here is what I am trying to do
And here is what I am trying to enforce
From the sound of it, an Enum would be more suited to what you're trying to do.
public enum MyConstants
{
FirstName,
LastName,
Title
}
public void CreateMe(Dictionary<MyConstants, string> propertyBag)
{
...
}
UPDATED
You could combine this with attributes to associate each enum with a specific string like so:
public enum PropertyNames
{
[Description("first_name")]
FirstName,
[Description("last_name")]
LastName,
[Description("title")]
Title
}
The value of each description attribute associated with each enum value could easily be grabbed via an extension method, like so:
public static class EnumExtensions
{
public static string GetDescription(this Enum value)
{
FieldInfo fieldInfo = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fieldInfo.GetCustomAttributes(
typeof(DescriptionAttribute),
false);
if (attributes != null &&
attributes.Length > 0)
return attributes[0].Description;
else
return value.ToString();
}
}
Then in your "CreateMe"-method you can get the description and value of each dictionary entry by doing something similar to this:
void CreateMe(Dictionary<PropertyNames, string> propertyBag)
{
foreach (var propertyPair in propertyBag)
{
string propertyName = propertyPair.Key.GetDescription();
string propertyValue = propertyPair.Value;
}
}
Even though this has been already answered, there is another approach, like so:
public class MyOwnEnum
{
public string Value { get; private set; }
private MyOwnEnum(string value)
{
Value = value;
}
public static readonly MyOwnEnum FirstName = new MyOwnEnum("Firstname");
public static readonly MyOwnEnum LastName = new MyOwnEnum("LastName");
}
It behaves same way like Enum and can be used in your code with same syntax. I cannot give credit to whoever came up with it, but I believe I came upon it when searching for Enums with multiple values.
With strings you can't enforce fact that keys come from limited set of vialues compile time.
Use enum or custom class (possibly with implicit conversion to string) instead.
I am trying to compare values that I am getting from web service, but sometimes I get int value, sometimes i get string. So it would be great that i could only check for Type.value1.
for example:
enum Type { value1 = 1 , value1="one"}
and like that for more value2, etc...
But of course, I cannot do this because it I cannot add two definitons for value1.
Sometimes a type that behaves mostly like an enum but has some richer behaviour can be very useful:
public sealed class MyFakeEnum {
private MyFakeEnum(int value, string description) {
Value = value;
Description = description;
}
public int Value { get; private set; }
public string Description { get; private set; }
// Probably add equality and GetHashCode implementations too.
public readonly static MyFakeEnum Value1 = new MyFakeEnum(1, "value1");
public readonly static MyFakeEnum Value2 = new MyFakeEnum(2, "value2");
}
You can consider adding attributes to the enums and use reflection.
enum Type
{
[Description("One")]
value1 = 1
}
I also make use of using decorating the enum with a description attribute as described by BSoD_ZA. But I would suggest that you then implement an extension method for the enumeration to obtain the string description for example:
public static class EnumExtension
{
public static string ToDescription<TEnum>(this TEnum enumValue) where TEnum : struct
{
return ReflectionService.GetClassAttribute<DescriptionAttribute>(enumValue);
}
}
enum Type
{
[Description("One")]
value1 = 1
}
var value = Type.Value1;
Console.Writeline(value.ToDescription());
I'm trying to set a custom enum property on a custom object by looking at a string value that is held in another object, but I keep getting the error "cannot reference a type through an expression."
so far I've tried
rec.Course = (CourseEnum)Enum.Parse(typeof(CourseEnum), rr.course);
where rec.Course wants a member of the CourseEnum Enumeration, and rr.course is a string.
I also tried to do a switch statement where the value of rr.course is checked (there are only certain values it can be) but get the same result
the enum is defined as follows:
public enum CourseEnum
{
[StringValue("Starters")]
Starters,
[StringValue("Main Course")]
MainCourse,
[StringValue("Desserts")]
Desserts
};
public class StringValue : System.Attribute
{
private string _value;
public StringValue(string value)
{
_value = value;
}
public string Value
{
get { return _value; }
}
}
public static class StringEnum
{
public static string GetStringValue(Enum value)
{
string output = null;
Type type = value.GetType();
//Check first in our cached results...
//Look for our 'StringValueAttribute'
//in the field's custom attributes
FieldInfo fi = type.GetRuntimeField(value.ToString());
StringValue[] attrs =
fi.GetCustomAttributes(typeof(StringValue),
false) as StringValue[];
if (attrs.Length > 0)
{
output = attrs[0].Value;
}
return output;
}
}
I can see in your code that your using Enum.Parse with CourseEnum and it should be recipeCourse I presume.
I can't spot any place in your sample code where4 CourseEnum is defined.
A #Hans Kesting said, the answer was here: Why can not reference a type through an expression?
The problem was using a field that has an enum type with the enum type itself.
I tried to search for an answer for this problem but could not find much, most probably because I do not know how to look for it properly, so here it goes. All help is very much appreciated.
With the base class that looks like
abstract public class Property
{
private String name;
public Property(String propertyName)
{
name = propertyName;
}
public String Name
{
get { return name; }
}
abstract public override String ToString();
}
And derived classes that look like
public class StringProperty : Property
{
private String value; // different properties for different types
public StringProperty(String propertyName, String value) : base(propertyName)
{
this.value = value;
}
public String Value // different signature for different properties
{
get { return value; }
}
public override String ToString()
{
return base.Name + ": " + value;
}
}
During runtime, the function receives a collection of "Property" objects. What do I need to do to be able to obtain the "Value" of each? Do I need to have a big if statement to query the type of each "Property" object? If not, is there a more elegant solution?
I tried to define an abstract "Value" property to be overridden but since the return types are different, it did not work. I also tried playing with shadowing the "Value" property, but I could not make it work. The idea of using an COM-like Variant does not sound very appropriate, either.
Thanks a lot in advance.
EDIT:
I should have added details as to what I am trying to do. The properties are displayed in a Winforms app. Different "TextBox"es represent different properties and are filtered for proper input (depending on the type). The updated values are read back and stored. The container object will be serialized into JSON and deserialized on an Android and iPhone client and eventually these values will be passed into a layer running native C++ code doing OpenGL stuff. I don't know in advance the kind of all needed properties so as the middleman, I wanted to make my code as robust as possible while being able to feed the OpenGL engine.
You can use a generic class:
public class AnyProperty<T> : Property
{
private T value;
// ... etc
I'd really recommend making the base class an Interface by now:
public interface IProperty
{
public String Name { get; }
}
public class Property<T> : IProperty
{
public Property(String name, T value)
{
Name = name;
Value = value;
}
public String Name { get; private set; }
public T Value { get; private set; }
public override String ToString()
{
return string.Format("{0}: {1}", Name, Value)
}
}
Here is sample usage:
var intProp = new Property<int> ("age", 32);
var strProp = new Property<string> ("name", "Earl");
var enumProp = new Property<ColorEnum> ("eye color", ColorEnum.Magenta);
To make the construction even simpler, you could have a factory method:
public static Property<T> MakeProperty(string name, T value)
{
return new Property<T>(name,value);
}
var intProp = MakeProperty("age", 32);
var strProp = MakeProperty("name", "Earl");
var enumProp = MakeProperty("eye color", ColorEnum.Magenta);
Not necessarily recommended, and a bit OT:
You could make it even funkier with an extension method:
public static Property<T> AsProp<T>(this T value, string name)
{
return new Property<T>(name,value);
}
var intProp = 32.AsProp("age");
var strProp = "Earl".AsProp("name");
var enumProp = ColorEnum.Magenta.AsProp("eye color");
You would have to simply use the object type. What are you trying to accomplish? The problem here isn't the structure of your classes, it's the function that receives the collection of Property objects. It's impossible to even cast something to an unknown type, since you don't know what type of variable it needs to be stored in.
So basically, your Property.Value property needs to be of type object. In your method that uses the Property objects, you need to do something with them, and what you're doing will decide how it should be structured. Are you printing values out? Have a *Value class inheriting from an abstract PropertyValue class and override ToString() to return an appropriate string represention.
I made a few changes to your sample code and got this result...
abstract public class Property
{
private readonly String _name;
public Property(String propertyName)
{
_name = propertyName;
}
public String Name
{
get { return _name; }
}
abstract public override String ToString();
}
public class StringProperty : Property
{
private readonly dynamic _value; // different properties for different types
public StringProperty(String propertyName, dynamic value)
: base(propertyName)
{
this._value = value;
}
public dynamic Value // different signature for different properties
{
get { return _value; }
}
public override String ToString()
{
return base.Name + ": " + _value;
}
}
static void Main(string[] args)
{
StringProperty sp = new StringProperty("A double", 3.444);
StringProperty sp2 = new StringProperty("My int", 4343);
StringProperty sp3 = new StringProperty("My directory", new DirectoryInfo("Some directory"));
StringProperty sp4 = new StringProperty("My null", null);
Console.WriteLine(sp);
Console.WriteLine(sp2);
Console.WriteLine(sp3);
Console.WriteLine(sp4);
}
}
Values are properly printed to the console in the expected way.
It would require a bit of a rethink, but have you considered using the dynamic type (introduced in .net4)
Doesn't really solve your problem, but sidespteps it.
Your properties can bascically just be a
Dictionary<String, dynamic>
, the gotcha is they don't get evaluated until runtime, so you get no compiler support for typing.
so given you want
int SomeValue = MyProperties[SomePropertyName] + 10;
So if
MyProperties[SomePropertyName] = 10; // all is good
if its 76.52 or Fred, the addition will throw an exception at the point it executes.
Code is much simpler and cleaner, no extra casting and the amount of scaffolding required is minimal, BUT, you'll need to unit test code that uses the dictionary extensively and religiously.