Set array values on class runtime (and set Attributes onto them)? - c#

I was unable to define what to name this problem, thus tried google and here, but cant find.
Is there any way to set array(or dictionary) members value on property level, and set attribute onto them? like this:
public class XYZ{
private string[] x= new string[]{"smth", "smth"};
x[0] { get; set; }
[Receipt(order=2, name="warranty")]
x[1] { get; set; }
....
}
So, mainly I have to questions to be frank:
1) Is that possible to set attributes onto array members?
2) Is that possible (forget attribute) to assign value to array member in property level (not within method), like this?:
public class XYZ{
private string[] x= new string[2]();
x[0] = "smth";
}

The answer is definitely no. Attributes can only be added onto compile-time features such as classes and methods. Not onto runtime features such as object data.
Also your getter/setter syntax is very wrong, it can only be like this:
public int Month { get; set; }
So an access modifier (public; optional), followed by a Type (int), followed by the name (Month), and then the get and/or set specification.

You can't do it exactly the way you want, but you can get close:
public class XYZ
{
private string[] x= new string[]{"smth", "smth"};
[Receipt(order=1, name="warranty")]
public string Receipt1 {get { return x[0];} set{x[0] = value;} }
[Receipt(order=2, name="warranty")]
public string Receipt2 {get { return x[1];} set{x[1] = value;} }
//...
}
Of course, the number of entries here are fixed, and you have to give these properties a real, meaningful name. You can't have a dynamic number of entries that changes while the program runs.
The one other thing you can look at is an indexer property. With an indexer, you can only set your attribute once on the whole property, rather than individual elements, but it will allow the number of items to change at run time.

The short answer is no. Attributes are for metadata, and this looks like actual data. Probably you should have your array be an array of some class that contains the value (i.e. smth) and all the data you wanted to have in your ReceiptAttribute.
So something like:
public class Receipt
{
public string Value {get; set;}
public int Order {get; set;}
public string Name {get; set;}
}
And then:
public class XYZ
{
private Receipt[] x= new Receipt[]
{
new Receipt() { Value = "smth", Order = 1, Name = "warranty" },
new Receipt() { Value = "smth", Order = 2, Name = "warranty" },
};
}
And, obviously, when you want the value you'd do something like:
x[0].Value

Related

C# - add attribute like '.Length' to custom class

I've playing around with a class that acts as a public interface for a private List<T> attribute. I noticed that the List<> class has an attribute Length that tells you how many elements it contains.
This is an attribute you cannot alter, and on the intellisense appears with an image of a spanner next to it. It is not a method as it does not require () after coding the name.
I've seen attributes of this type before, but never used them in my own classes. Does anybody have any idea how I can replicate Length in my custom class?
Thanks,
Mark
It's a property with no setter. If you're wrapping a List<T> you can just use it's Count as your own:
public int Count {get {return _myPrivateList.Count; } }
If you're using C# 6, you can use this:
public int Count => _myPrivateList.Count;
If you currently have a class that contains a List, then you can take advantage of the Count property already present on it by exposing a property that simply uses that :
public class YourExampleList<T>
{
// Example of your inner list
private List<T> _list { get; set; }
// Use the Count property to expose a public "Length" equivalent
public int Length { get { return _list.Count; } }
}
This is actually not a method, but a property.
So you could have define in your class
private List<string> myList = new List<string>();
public int NumberOfElements
{
get { return this.myList.Count; }
}
A normal property would be defined such as
public bool ColumnNames { get; set; }
List<T> myList = new List<T>();
Now you can create your own implementation on your custom class. Something like:
public int Length {get {return myList.Count; }}
I must admit that your question is a bit vague. It sounds like you want know how to create a read only attribute / property. This can be achieved by creating a property wrapper for a private field member of your class as follow:
class MyCustomClass
{
private int _length;
public int Length
{
get { return _length; }
}
}
Say for example you have a class like this:
public class MyClass
{
private string _str;
public MyClass()
{
_str = "Sample String";
}
public int Length
{
get
{
return _str.Length;
}
}
}
This is what's happening:
We're declaring a private field at the start of the class named _str.
In the constructor we're then assigning it a value of "Sample String".
After the constructor we're then declaring the public attribute Length of type int, and only giving it a get accessor. Like your example, this only allows the value to be read, and not set.
Within the get we then tell it to return the value of _str's length.
Using code similar to this you can implement a Length attribute for any custom class.

Auto-Implemented Properties [duplicate]

How do you give a C# auto-property an initial value?
I either use the constructor, or revert to the old syntax.
Using the Constructor:
class Person
{
public Person()
{
Name = "Initial Name";
}
public string Name { get; set; }
}
Using normal property syntax (with an initial value)
private string name = "Initial Name";
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
Is there a better way?
In C# 5 and earlier, to give auto implemented properties an initial value, you have to do it in a constructor.
Since C# 6.0, you can specify initial value in-line. The syntax is:
public int X { get; set; } = x; // C# 6 or higher
DefaultValueAttribute is intended to be used by the VS designer (or any other consumer) to specify a default value, not an initial value. (Even if in designed object, initial value is the default value).
At compile time DefaultValueAttribute will not impact the generated IL and it will not be read to initialize the property to that value (see DefaultValue attribute is not working with my Auto Property).
Example of attributes that impact the IL are ThreadStaticAttribute, CallerMemberNameAttribute, ...
Edited on 1/2/15
C# 6 :
With C# 6 you can initialize auto-properties directly (finally!), there are now other answers that describe that.
C# 5 and below:
Though the intended use of the attribute is not to actually set the values of the properties, you can use reflection to always set them anyway...
public class DefaultValuesTest
{
public DefaultValuesTest()
{
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(this))
{
DefaultValueAttribute myAttribute = (DefaultValueAttribute)property.Attributes[typeof(DefaultValueAttribute)];
if (myAttribute != null)
{
property.SetValue(this, myAttribute.Value);
}
}
}
public void DoTest()
{
var db = DefaultValueBool;
var ds = DefaultValueString;
var di = DefaultValueInt;
}
[System.ComponentModel.DefaultValue(true)]
public bool DefaultValueBool { get; set; }
[System.ComponentModel.DefaultValue("Good")]
public string DefaultValueString { get; set; }
[System.ComponentModel.DefaultValue(27)]
public int DefaultValueInt { get; set; }
}
When you inline an initial value for a variable it will be done implicitly in the constructor anyway.
I would argue that this syntax was best practice in C# up to 5:
class Person
{
public Person()
{
//do anything before variable assignment
//assign initial values
Name = "Default Name";
//do anything after variable assignment
}
public string Name { get; set; }
}
As this gives you clear control of the order values are assigned.
As of C#6 there is a new way:
public string Name { get; set; } = "Default Name";
Sometimes I use this, if I don't want it to be actually set and persisted in my db:
class Person
{
private string _name;
public string Name
{
get
{
return string.IsNullOrEmpty(_name) ? "Default Name" : _name;
}
set { _name = value; }
}
}
Obviously if it's not a string then I might make the object nullable ( double?, int? ) and check if it's null, return a default, or return the value it's set to.
Then I can make a check in my repository to see if it's my default and not persist, or make a backdoor check in to see the true status of the backing value, before saving.
In C# 6.0 this is a breeze!
You can do it in the Class declaration itself, in the property declaration statements.
public class Coordinate
{
public int X { get; set; } = 34; // get or set auto-property with initializer
public int Y { get; } = 89; // read-only auto-property with initializer
public int Z { get; } // read-only auto-property with no initializer
// so it has to be initialized from constructor
public Coordinate() // .ctor()
{
Z = 42;
}
}
Starting with C# 6.0, We can assign default value to auto-implemented properties.
public string Name { get; set; } = "Some Name";
We can also create read-only auto implemented property like:
public string Name { get; } = "Some Name";
See: C# 6: First reactions , Initializers for automatically implemented properties - By Jon Skeet
In Version of C# (6.0) & greater, you can do :
For Readonly properties
public int ReadOnlyProp => 2;
For both Writable & Readable properties
public string PropTest { get; set; } = "test";
In current Version of C# (7.0), you can do : (The snippet rather displays how you can use expression bodied get/set accessors to make is more compact when using with backing fields)
private string label = "Default Value";
// Expression-bodied get / set accessors.
public string Label
{
get => label;
set => this.label = value;
}
In C# 9.0 was added support of init keyword - very useful and extremly sophisticated way for declaration read-only auto-properties:
Declare:
class Person
{
public string Name { get; init; } = "Anonymous user";
}
~Enjoy~ Use:
// 1. Person with default name
var anonymous = new Person();
Console.WriteLine($"Hello, {anonymous.Name}!");
// > Hello, Anonymous user!
// 2. Person with assigned value
var me = new Person { Name = "#codez0mb1e"};
Console.WriteLine($"Hello, {me.Name}!");
// > Hello, #codez0mb1e!
// 3. Attempt to re-assignment Name
me.Name = "My fake";
// > Compilation error: Init-only property can only be assigned in an object initializer
In addition to the answer already accepted, for the scenario when you want to define a default property as a function of other properties you can use expression body notation on C#6.0 (and higher) for even more elegant and concise constructs like:
public class Person{
public string FullName => $"{First} {Last}"; // expression body notation
public string First { get; set; } = "First";
public string Last { get; set; } = "Last";
}
You can use the above in the following fashion
var p = new Person();
p.FullName; // First Last
p.First = "Jon";
p.Last = "Snow";
p.FullName; // Jon Snow
In order to be able to use the above "=>" notation, the property must be read only, and you do not use the get accessor keyword.
Details on MSDN
In C# 6 and above you can simply use the syntax:
public object Foo { get; set; } = bar;
Note that to have a readonly property simply omit the set, as so:
public object Foo { get; } = bar;
You can also assign readonly auto-properties from the constructor.
Prior to this I responded as below.
I'd avoid adding a default to the constructor; leave that for dynamic assignments and avoid having two points at which the variable is assigned (i.e. the type default and in the constructor). Typically I'd simply write a normal property in such cases.
One other option is to do what ASP.Net does and define defaults via an attribute:
http://msdn.microsoft.com/en-us/library/system.componentmodel.defaultvalueattribute.aspx
My solution is to use a custom attribute that provides default value property initialization by constant or using property type initializer.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class InstanceAttribute : Attribute
{
public bool IsConstructorCall { get; private set; }
public object[] Values { get; private set; }
public InstanceAttribute() : this(true) { }
public InstanceAttribute(object value) : this(false, value) { }
public InstanceAttribute(bool isConstructorCall, params object[] values)
{
IsConstructorCall = isConstructorCall;
Values = values ?? new object[0];
}
}
To use this attribute it's necessary to inherit a class from special base class-initializer or use a static helper method:
public abstract class DefaultValueInitializer
{
protected DefaultValueInitializer()
{
InitializeDefaultValues(this);
}
public static void InitializeDefaultValues(object obj)
{
var props = from prop in obj.GetType().GetProperties()
let attrs = prop.GetCustomAttributes(typeof(InstanceAttribute), false)
where attrs.Any()
select new { Property = prop, Attr = ((InstanceAttribute)attrs.First()) };
foreach (var pair in props)
{
object value = !pair.Attr.IsConstructorCall && pair.Attr.Values.Length > 0
? pair.Attr.Values[0]
: Activator.CreateInstance(pair.Property.PropertyType, pair.Attr.Values);
pair.Property.SetValue(obj, value, null);
}
}
}
Usage example:
public class Simple : DefaultValueInitializer
{
[Instance("StringValue")]
public string StringValue { get; set; }
[Instance]
public List<string> Items { get; set; }
[Instance(true, 3,4)]
public Point Point { get; set; }
}
public static void Main(string[] args)
{
var obj = new Simple
{
Items = {"Item1"}
};
Console.WriteLine(obj.Items[0]);
Console.WriteLine(obj.Point);
Console.WriteLine(obj.StringValue);
}
Output:
Item1
(X=3,Y=4)
StringValue
little complete sample:
using System.ComponentModel;
private bool bShowGroup ;
[Description("Show the group table"), Category("Sea"),DefaultValue(true)]
public bool ShowGroup
{
get { return bShowGroup; }
set { bShowGroup = value; }
}
You can simple put like this
public sealed class Employee
{
public int Id { get; set; } = 101;
}
In the constructor. The constructor's purpose is to initialized it's data members.
private string name;
public string Name
{
get
{
if(name == null)
{
name = "Default Name";
}
return name;
}
set
{
name = value;
}
}
Have you tried using the DefaultValueAttribute or ShouldSerialize and Reset methods in conjunction with the constructor? I feel like one of these two methods is necessary if you're making a class that might show up on the designer surface or in a property grid.
Use the constructor because "When the constructor is finished, Construction should be finished". properties are like states your classes hold, if you had to initialize a default state, you would do that in your constructor.
To clarify, yes, you need to set default values in the constructor for class derived objects. You will need to ensure the constructor exists with the proper access modifier for construction where used. If the object is not instantiated, e.g. it has no constructor (e.g. static methods) then the default value can be set by the field. The reasoning here is that the object itself will be created only once and you do not instantiate it.
#Darren Kopp - good answer, clean, and correct. And to reiterate, you CAN write constructors for Abstract methods. You just need to access them from the base class when writing the constructor:
Constructor at Base Class:
public BaseClassAbstract()
{
this.PropertyName = "Default Name";
}
Constructor at Derived / Concrete / Sub-Class:
public SubClass() : base() { }
The point here is that the instance variable drawn from the base class may bury your base field name. Setting the current instantiated object value using "this." will allow you to correctly form your object with respect to the current instance and required permission levels (access modifiers) where you are instantiating it.
public Class ClassName{
public int PropName{get;set;}
public ClassName{
PropName=0; //Default Value
}
}
This is old now, and my position has changed. I'm leaving the original answer for posterity only.
Personally, I don't see the point of making it a property at all if you're not going to do anything at all beyond the auto-property. Just leave it as a field. The encapsulation benefit for these item are just red herrings, because there's nothing behind them to encapsulate. If you ever need to change the underlying implementation you're still free to refactor them as properties without breaking any dependent code.
Hmm... maybe this will be the subject of it's own question later
class Person
{
/// Gets/sets a value indicating whether auto
/// save of review layer is enabled or not
[System.ComponentModel.DefaultValue(true)]
public bool AutoSaveReviewLayer { get; set; }
}
I know this is an old question, but it came up when I was looking for how to have a default value that gets inherited with the option to override, I came up with
//base class
public class Car
{
public virtual string FuelUnits
{
get { return "gasoline in gallons"; }
protected set { }
}
}
//derived
public class Tesla : Car
{
public override string FuelUnits => "ampere hour";
}
I think this would do it for ya givng SomeFlag a default of false.
private bool _SomeFlagSet = false;
public bool SomeFlag
{
get
{
if (!_SomeFlagSet)
SomeFlag = false;
return SomeFlag;
}
set
{
if (!_SomeFlagSet)
_SomeFlagSet = true;
SomeFlag = value;
}
}

Change an item property received from a linq query

I need to change the value of an item of a list returned by a query... It must be simple, but i can´t see it using linq.
The list is composed by elements of this structure:
public struct HeaderButton
{
public string content {get; set;}
public BitmapImage icon {get; set;}
public PageContainerFactory.ContainerType containerType {get; set;}
public bool IsSelected { get; set; }
}
private List<HeaderButton> _headerButtons;
public List<HeaderButton> HeaderButtons
{
get
{
if (_headerButtons == null)
_headerButtons = new List<HeaderButton>();
return _headerButtons;
}
set { _headerButtons = value; }
}
I´ve tried this:
HeaderButtons.First(x => x.containerType == CurrentContainer.CType).IsSelected = true;
And the compiler tells me:
Cannot modify the return value of 'System.Linq.Enumerable.First(System.Collections.Generic.IEnumerable, System.Func)' because it is not a variable
And now the query that i´m trying:
var h = HeaderButtons.First(x => x.containerType == CurrentContainer.CType);
h.IsSelected = true;
I had to take the element in a var because of the compiler error. And doing it as represented in the code above, obviously "h" does not points to the "HeaderButtons" real element since it is a new HeaderButton object and not a reference.
Following your comments, i decided to make a nested class in place of the structure since this kind of objects are not used outside of the content class, and now that is a class (object reference) and not a struct (value), everything works fine.
The code:
sealed class MainViewModel : ViewModelNavigator
{
internal class HeaderButton
{
public string Content { get; set; }
public BitmapImage Icon { get; set; }
public PageContainerFactory.ContainerType ContainerType { get; set; }
public bool IsSelected { get; set; }
}
...
private List<HeaderButton> _headerButtons;
public List<HeaderButton> HeaderButtons
{
get
{
if (_headerButtons == null)
_headerButtons = new List<HeaderButton>();
return _headerButtons;
}
set { _headerButtons = value; }
}
...
HeaderButtons.First(x => x.ContainerType == CurrentContainer.CType).IsSelected = true;
The compiler is saving you from shooting yourself in the foot.
Because HeaderButton is a struct it is passed by value instead of by reference. Which means that the Linq First operator is acting on (and will return) a value copy of the element in the list.
Because the return value from First is not assigned to anything it is temporary and will go out of scope at the end of the statement, and what's more since it is a value copy and not a reference to the item in the list any changes you make to it will not affect the item in the list anyway.
If this were to compile you might easily be misled to thinking that you had updated the item in the list, which you would not have. By refusing to compile the compiler is saving you from having to track down what could be a tricky bug to find.
If you have reason to keep HeaderButton as a struct then a statement like this will enable you to update it.
var hb = HeaderButtons.First(x => x.containerType == CurrentContainer.CType);
HeaderButtons[HeaderButtons.IndexOf(hb)].IsSelected = true;
If you go this route you need to ensure your struct's equality operations behave in a way that is useful to you, which hinges on the same factors as 'If you have reason to keep HeaderButton as a struct' because part of wanting to use a struct instead of a class means wanting value equality instead of reference equality semantics.

How do you make an 'enum' that has data tied to it?

I have a Vote class and one of the properties it can have is a vote type. Such as unanimous, a 3/4 vote, a simply majority, etc. Each type needs to have a string associated with it which will describe the vote type (like "A simply majority requires 51% to pass" etc.). I need to pass these vote types/description in with my view model to my view and then I can make my drop down list with it.
Then, when the form that creates the vote is submitted I just need to bind the vote type (without description) to the Vote model (which is part of the view model).
I've only been using C# for a short time and I don't quite understand how the enums work in it. Perhaps enum is not the way to go about this.
public class VoteViewModel
{
public VoteViewModel()
{
Vote = new Vote();
}
public Vote Vote { get; set; }
public int EligibleVoters { get; set; }
}
And this is where I'll be putting the drop down.
<section class="vote-type">
<select name="">
<option value="">Select Vote Type</option>
</select>
<section class="vote-type-info">
<p class="vote-rules">To pass this vote, at least 51% of Eligible Voters must vote to approve it.</p>
</section>
</section>
Please notice I'm only showing for strings for it could be any type. In each case I mention how to extend it for more values if possible.
Using the enum as a key
You can use your enum type as a key for a dictionary (you want to be unique, so make it static and readonly in some helper class):
private static readonly Dictionary<MyEnum, string> _dict =
{
//Using dictionary initialization
{MyEnum.MyValue, "The text for MyValue"},
{MyEnum.MyOtherValue, "Some other text"},
{MyEnum.YetAnotherValue, "Something else"}
}
public static readonly Dictionary<MyEnum, string> Dict
{
get
{
return _dict;
}
}
And access the associated value:
string text = Dict[MyEnum.MyValue];
Or with:
string text;
if (Dict.TryGetValue(MyEnum.MyValue, out text))
{
//It has the value
}
else
{
//It doesn't have the value
}
This way you can access a string that is associated with the enum value. Then you can expose your Dictionary so that you can read the corresponding values.
You will need a complex type for storing more than one value. Just use your custom type isntead of string. Or if available you can use Tuples.
Accesing the Dictionary may mean an extra annoyance and hopefully it will not mean a threading problem too.
Enum.GetName
You can use Enum.GetName to read the name of the values of your enum:
string text = Enum.GetName(MyEnum.MyValue);
//text will have the text "MyValue"
//or
var some = MyEnum.MyValue;
string text = Enum.GetName(some);
Note: ToString() should work too.
Sadly, this will not work for something else than the string.
Also it has the drawback that you cannot put any text there (it has to be a valid identifier).
Custom Attributes
You will have to declare an attribute type:
[AttributeUsage(AttributeTargets.Field)]
public class EnumValueAttribute : System.Attribute
{
public readonly string _value;
public string Value
{
get
{
return _value;
}
}
public EnumValueAttribute(string value) // value is a positional parameter
{
//beware: value can be null...
// ...but we don't want to throw exceptions here
_value = value;
}
}
Now you apply the attribute to your enum:
public enum MyEnum
{
[EnumValue("The text for MyValue")]
MyValue = 1,
[EnumValue("Some other text")]
MyOtherValue = 2,
[EnumValue("Something else")]
YetAnotherValue = 3
}
Lastly you will need to read the attribute back:
public static string GetValue(MyEnum enumValue)
{
FieldInfo fieldInfo = typeof(MyEnum).GetField(enumValue.ToString());
if (!ReferenceEquals(fieldInfo, null))
{
object[] attributes = fieldInfo.GetCustomAttributes(typeof(EnumValueAttribute), true);
if (!ReferenceEquals(attributes, null) && attributes.Length > 0)
{
return ((EnumValueAttribute)attributes[0]).Value;
}
}
//Not valid value or it didn't have the attribute
return null;
}
Now you can call it:
string text1 = GetValue(MyEnum.MyValue);
//text1 will have the text "MyValue"
//or
var some = MyEnum.MyValue;
string text2 = GetValue(some);
You can add more fields to your attribute class and use them to pass any other value you may need.
But this requires reflexion, and it may not be available if you are running in a sandbox. Also it will retrieve the attributes each time, creating some short lived objects in the proccess.
Emulate Enum
You can emulate an enum with a sealed class that has no public constructor and exposes static readonly instances of itself:
public sealed class MyEnumEmu
{
private static readonly string myValue = new MyEnumEmu("The text for MyValue");
private static readonly string myOtherValue = new MyEnumEmu("Some other text");
private static readonly string yetAnotherValue = new MyEnumEmu("Something else");
public static MyEnumEmu MyValue
{
get
{
return myValue;
}
}
public static MyEnumEmu MyOtherValue
{
get
{
return myOtherValue;
}
}
public static MyEnumEmu YetAnotherValue
{
get
{
return yetAnotherValue;
}
}
private string _value;
private MyEnumEmu(string value)
{
//Really, we are in control of the callers of this constructor...
//... but, just for good measure:
if (value == null)
{
throw new ArgumentNullException("value");
}
else
{
_value = value;
}
}
public string Value
{
get
{
return _value;
}
}
}
Use it as always:
var some = MyEnumEmu.MyValue;
And access the associated value:
string text = MyEnumEmu.MyValue.Value;
//text will have the text "MyValue"
//or
string text = some.Value;
This is the more flexible of all, you can either use a complex type instead of string or add extra fields for passing more than a single value.
But... it is not really an enum.
You could create a "constant" dictionary (or rather readonly static, since you can't create a constant dictionary) around your Enum.
public enum VoteType { Unanimous = 1, SimpleMajority = 2, ... }
public static readonly Dictionary<VoteType, string> VoteDescriptions = new Dictionary<VoteType, string>
{
{ VoteType.Unanimous, "Unanimous description" },
{ VoteType.SimpleMajority, "Simple majority" },
...
};
public class Vote()
{
public VoteType VoteSelectType { get; set; }
}
public enum VoteType
{
[Display(Name = "Enter Text Here")]
unanimous = 1,
[Display(Name = "Enter Text Here")]
threequatervote = 2,
[Display(Name = "Enter Text Here")]
simplymajority = 3
}
Goto here this is pretty much your solution
How do I populate a dropdownlist with enum values?
You can use enums if you want but you need to decide how to make the link between the enum value and what you want to display. For example, an enum value of SimpleMajority you would want displayed as "Simple Majority". One way to do this is using the Description attribute and a helper class as described here.
However, you might find it easier to set up a lightweight collection class to store vote type values and their description. This could be as simple as a Dictionary<int, string> You will probably find this a more straightforward approach.
Since you have the type and description I'll better suggest you to create a class that wraps up both instead of enum. The advantage is you can reduce more work and it's very flexible.
public class VoteType
{
public string Name{ get; set; }
public string Description{ get; set; }
}
Now your Vote class will have reference to this VoteType.
public class Vote
{
...
public VoteType Type{ get; set; }
}
In your VoteViewModel you better have a class that contains all the VoteTypes.
public class VoteViewModel
{
...
public IEnumerable<SelectListItem> VoteTypes{ get; set; }
}
Now you can easily bind the VoteTypes in a dropdownlist.
#model VoteViewModel
#Html.DropDiwnListFor(m => m.VoteTypes,...)
I have used this before, it is really handy.
http://www.codeproject.com/Articles/13821/Adding-Descriptions-to-your-Enumerations
In short what it lets you do is:
public enum MyColors{
[Description("The Color of my skin")]
White,
[Description("Bulls like this color")]
Red,
[Description("The color of slime")]
Green
}
and then get the description back by simply calling:
String desc = GetDescription(MyColor.Green);
It does use reflection though, so there is a tradeoff between simplicity and a slight performance hit. Most of the time I'd take the performance hit...

Is using an Enum the best way to go for listing different "Types of Car"

I have an attribute in my car class called VehicleType.
Using an enum, I could list the different types of cars that exist and not allow any other type to be hard written in.
Problem is, if I have to GET the attribute from somewhere else, I will GET a numberical value, and not the string literal I saved.
What should I use here?
class Hero
{
public string faction;
public string name;
public string herotype;
enum HeroType
{
Agility,
Strength,
Intelligence,
}
}
You could create an abstract base class
public abstract class BaseHero
{
public string faction;
public string name;
...... more properties
}
and then derive your heroes from that:
public class AgilityHero : BaseHero
{
}
public class StrengthHero : BaseHero
{
}
public class IntelligenceHero : BaseHero
{
}
Common stuff would be handled and coded in the base class, those things specific to a hero type in the actual hero class.
Using this OO approach, you can save yourself from having to write, code, maintain a lot of if....then.....else or switch statements in your Hero class - the differences are handled by the fact of having different types for each type of hero.
What? Why would you have a string literal and an enum? Your class should look like this:
class Hero
{
public string faction;
public string name;
public HeroType herotype; // <-- not a string
enum HeroType
{
Agility,
Strength,
Intelligence,
}
}
The "string" version is just the enum so it's easier for you to remember, but shouldn't actually be saved as a string anywhere (except if you need to display it to the user).
Whether an enum is approriate depends entirely on your design. If you have a fixed number of possible values, then an enum may be a good approach.
In C# you can convert between an Enumerated type and its string representation using Enum.ToString() and Enum.Parse(), so it is trivially easy to serialise an enum's value and disallow "illegal" values when reloading the data. There is no need to serialise it as an integer value.
(The one caveat of this is if you use obfuscation, you must make sure not to obfuscate the enumerated type)
If you have to store the enum as an integer value, then there is no problem with that, as long as you don't change the values of the enum entries - add new entries at the end of the enum's list, but don't insert new entries in the middle of it.
What I sometimes do for modeling richer 'enumeration-like' types is the following:
public enum HeroTypeValue
{
Agility,
Strength,
Intelligence
}
public class HeroType
{
public HeroTypeValue Value { get; set; }
public string Description { get; set; }
// ... other properties and possibly behaviour, as needed
public static HeroType Agility = new HeroType
{
ID = HeroTypeValue.Agility,
Description = "Agility"
},
public static HeroType Strength = new HeroType
{
ID = HeroTypeValue.Strength,
Description = "Agility"
};
public static HeroType Intelligence = new HeroType
{
ID = HeroTypeValue. Intelligence,
Description = "Intelligence"
};
public static IEnumerable<HeroType> All = new []
{
Agility,
Strength,
Intelligence
}
}
This allows to do data binding with easily customizable descriptions, when needed you can also synchronize with a table in the database.
You can of course combine it with the answer by marc_s, making the HeroType a (abstract or not) base class for added OO value.

Categories

Resources