Given a string with the same name of an object field, how can I get the reference to the object field?
For example, say I pass in a string called "field1" to the GetFieldByStr method, and the object has an field name field1, how can I get a reference to the field1 object? I'm assuming using reflection somehow.
class Example {
private FieldExample attr1;
void GetFieldByStr(String str) {
// We get passed in "field1" as a string, now I want
// to get the field1 attribute.
}
}
You need to use Reflection:
FieldInfo field = typeof(Example).GetField(str);
object value = field.GetValue(this);
(For properties, use PropertyInfo)
Note that value is an object; in order to do anything useful with it, you'll need to cast it to some class or interface (or use dynamic in C# 4).
Here's an idea that doesn't rely on reflection. The downside is that it requires some setup. You could possibly even define some custom attributes and use some clever code to perform the setup automatically on application start.
interface IAttributeStore
{
T GetAttribute<T>(string key);
}
class Example : IAttributeStore
{
public int ExampleID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
static Dictionary<string, Delegate> _AttributeAccessors;
static Example()
{
_AttributeAccessors = new Dictionary<string, Delegate>();
_AttributeAccessors.Add("ExampleID", new Func<Example, int>((example) => example.ExampleID));
_AttributeAccessors.Add("FirstName", new Func<Example, string>((example) => example.FirstName));
_AttributeAccessors.Add("LastName", new Func<Example, string>((example) => example.LastName));
}
#region IAttributeStore Members
public T GetAttribute<T>(string key)
{
Delegate accessor;
if (_AttributeAccessors.TryGetValue(key, out accessor))
{
Func<Example, T> func = accessor as Func<Example, T>;
if (func != null)
return func(this);
else
throw new Exception(string.Format("The attribute with the given key \"{0}\" is not of type [{1}].", key, typeof(T).FullName));
}
else
{
throw new ArgumentException(string.Format("No attribute exists with the given key: \"{0}\".", key), "key");
}
}
#endregion
}
class Program
{
static void Main(string[] args)
{
Example example = new Example() { ExampleID = 12345, FirstName = "Funky", LastName = "Town" };
Console.WriteLine(example.GetAttribute<int>("ExampleID"));
Console.WriteLine(example.GetAttribute<string>("FirstName"));
Console.WriteLine(example.GetAttribute<string>("LastName"));
}
}
Update: This seemed interesting to me, so I threw together an alternative implementation that utilizes attributes and extension methods instead of an interface. The nice thing about this is that it requires very little code per class (you just need to add the attributes), and the code that sets up the delegates only runs if the application actually requests an attribute from a particular class.
I have to give credit to Marc Gravell's answer to this question for how to dynamically create a delegate for getting a property given a PropertyInfo object.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, AllowMultiple = false, Inherited = true)]
class AttributeStoreAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
class StoredAttributeAttribute : Attribute
{
public string Key { get; set; }
}
public static class AttributeStore<T>
{
static Dictionary<string, Delegate> _AttributeAccessors;
public static void Initialize()
{
_AttributeAccessors = new Dictionary<string, Delegate>();
Type type = typeof(T);
// let's keep it simple and just do properties for now
foreach (var property in type.GetProperties())
{
var attributes = property.GetCustomAttributes(typeof(StoredAttributeAttribute), true);
if (attributes != null && attributes.Length > 0)
{
foreach (object objAttribute in attributes)
{
StoredAttributeAttribute attribute = objAttribute as StoredAttributeAttribute;
if (attribute != null)
{
string key = attribute.Key;
// use the property name by default
if (string.IsNullOrEmpty(key))
key = property.Name;
if (_AttributeAccessors.ContainsKey(key))
throw new Exception(string.Format("An attribute accessor has already been defined for the given key \"{0}\".", key));
Type typeOfFunc = typeof(Func<,>).MakeGenericType(type, property.PropertyType);
Delegate accessor = Delegate.CreateDelegate(typeOfFunc, null, property.GetGetMethod());
_AttributeAccessors.Add(key, accessor);
}
}
}
}
}
public static object GetAttribute(T store, string key)
{
if (_AttributeAccessors == null)
Initialize();
Delegate accessor;
if (_AttributeAccessors.TryGetValue(key, out accessor))
{
return accessor.DynamicInvoke(store);
}
else
{
throw new ArgumentException(string.Format("No attribute exists with the given key: \"{0}\" on attribute store [{1}].", key, typeof(T).FullName), "key");
}
}
public static TResult GetAttribute<TResult>(T store, string key)
{
if (_AttributeAccessors == null)
Initialize();
Delegate accessor;
if (_AttributeAccessors.TryGetValue(key, out accessor))
{
Func<T, TResult> func = accessor as Func<T, TResult>;
if (func != null)
return func(store);
else
throw new Exception(string.Format("The attribute with the given key \"{0}\" on attribute store [{1}] is not of type [{2}].", key, typeof(T).FullName, typeof(TResult).FullName));
}
else
{
throw new ArgumentException(string.Format("No attribute exists with the given key: \"{0}\" on attribute store [{1}].", key, typeof(T).FullName), "key");
}
}
}
public static class AttributeStoreExtensions
{
public static object GetAttribute<T>(this T store, string key)
{
return AttributeStore<T>.GetAttribute(store, key);
}
public static TResult GetAttribute<T, TResult>(this T store, string key)
{
return AttributeStore<T>.GetAttribute<TResult>(store, key);
}
}
[AttributeStore]
class Example
{
[StoredAttribute]
public int ExampleID { get; set; }
[StoredAttribute]
public string FirstName { get; set; }
[StoredAttribute]
public string LastName { get; set; }
}
[AttributeStore]
class Example2
{
[StoredAttribute]
[StoredAttribute(Key = "ID")]
public int ExampleID { get; set; }
[StoredAttribute]
[StoredAttribute(Key = "First")]
public string FirstName { get; set; }
[StoredAttribute]
[StoredAttribute(Key = "Last")]
public string LastName { get; set; }
}
class Program
{
static void Main(string[] args)
{
Example example = new Example() { ExampleID = 12345, FirstName = "Funky", LastName = "Town" };
Console.WriteLine(example.GetAttribute("ExampleID"));
Console.WriteLine(example.GetAttribute("FirstName"));
Console.WriteLine(example.GetAttribute("LastName"));
Example2 example2 = new Example2() { ExampleID = 12345, FirstName = "Funky", LastName = "Town" };
// access attributes by the default key (property name)
Console.WriteLine(example2.GetAttribute("ExampleID"));
Console.WriteLine(example2.GetAttribute("FirstName"));
Console.WriteLine(example2.GetAttribute("LastName"));
// access attributes by the explicitly specified key
Console.WriteLine(example2.GetAttribute("ID"));
Console.WriteLine(example2.GetAttribute("First"));
Console.WriteLine(example2.GetAttribute("Last"));
}
}
You can do so with the Reflection library (either FieldInfo or PropertyInfo depending if you want a field or a property)
Example:
void GetAttributesByStr(String str) {
FieldInfo attributeInfo = this.GetType().GetField(str); // you might want to use some Binding flags here like BindingFlags.Instance and BindingFlags.Public
attributeInfo.GetValue(this); // assign this to something or return it as an object
}
For properties.
var prop = this.GetType().GetProperty(str);
prop.GetValue(prop, null);
Related
I have a C# code that would look at every public-property on a class and creates a collection of the key and value. The key is simply a dot-notation variable to access the property;
I have the following models
public class Home
{
public string Id { get; set; }
public string Summary { get; set; }
public Address Address { get; set; }
}
public class Address
{
public Street Street { get; set; }
public string CityName { get; set; }
public string StateName { get; set; }
}
public class Street
{
public string Number { get; set; }
public string Name { get; set; }
}
Then I have the following function
public void GetPropertyKeyValue<T>(T obj, string prefix, List<ExtractedTerm> pairs)
{
if (pairs == null)
{
throw new ArgumentNullException(nameof(pairs));
}
// This works of the first object, but fails on the class properties
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach (var property in properties)
{
string key = property.Name;
if (!string.IsNullOrWhiteSpace(prefix))
{
key = $"{prefix}.{property.Name}";
}
Type type = property.PropertyType;
object value = property.GetValue(obj, null);
if (type.IsClass && !type.IsInterface && !type.IsEnum && !type.IsPrimitive && !type.IsString())
{
GetPropertyKeyValue(value, key, ref pairs);
continue;
}
pairs.Add(new ExtractedTerm(key, value, property.PropertyType));
}
}
The above method is called like this
var home = new Home() {
Id = "100",
Summary = "Test",
Address = new Address() {
CityName = "Los Angeles"
}
}
var pairs = new List<ExtractedTerm>();
GetPropertyKeyValue(home, null, pairs);
The above code works perfectly on the Home.Id and Home.Summary and Home.Address But sine the Address is property of a class type, so the GetPropertyKeyValue method is recursively being called. When Address is passed the code typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance) does not return any properties. However, the code obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance) returns the properties expected. But I can't really count of obj.GetType() as obj could be null. As you noticed in the example above the Street property is null and obj.GetType() will throw an exception.
Why typeof() works in some cases but not always? How can I get the properties always even when obj is null?
Type inference happens at compile time.
In other words, since value is of static type object,
object value = property.GetValue(obj, null);
the following line:
GetPropertyKeyValue(value, key, ref pairs);
gets compiled as
GetPropertyKeyValue<object>(value, key, ref pairs);
and typeof(object) yields ... well ... the object type.
How to solve this? Instead of making the method generic, pass in a parameter of type Type. That way, you can just pass property.PropertyType in the recursive invocation. I would suggest the following signature:
public void GetPropertyKeyValue<T>(T obj, string prefix, List<ExtractedTerm> pairs)
{
return GetPropertyKeyValue(typeof(T), obj, prefix, pairs);
}
private void GetPropertyKeyValue(Type type, object obj, string prefix, List<ExtractedTerm> pairs)
{
// contains your logic and recursively calls the non-generic version
...
}
Try this:
public Dictionary<string, object> GetPropertyKeyValue(string ClassName)
{
Dictionary<string, object> Values = new Dictionary<string, object>();
System.Reflection.PropertyInfo[] Properties = System.Reflection.Assembly.GetExecutingAssembly().GetTypes().First(x => x.Name == ClassName).GetProperties();
foreach (System.Reflection .PropertyInfo property in Properties)
{
Values.Add(property.Name, property.GetValue(System.Reflection.Assembly.GetExecutingAssembly().GetTypes().First(x => x.Name == ClassName)));
}
return Values;
}
I have two different classes. And, those two different classes have multiple properties as well. Consider the following two example classes,
public Class1{
public string Key;
public string value;
}
public Class2{
public string Key;
public string value;
}
Note: For example, I added the class like above. But, in reality, the two classes should have different values with the same name.
These classes should be a member of the list like below,
List<Class1> list1 = new List<Class1>();
List<Class2> list2 = new List<Class2>();
So, to process these list I need a two different functions something like below,
private string GetStrValue(List<Class1> values)
{
string toRet = string.Empty;
if (values == null)
return toRet;
foreach (Class1 val in values)
{
if (!string.IsNullOrWhiteSpace(val.Key)) {
toRet = val.value;
break;
}
}
return toRet;
}
And, the similar function to process the Int class as well. So, I planned to use the generic. I have written the code like below,
private string GetValue<T>(List<T> listValue)
{
string toRet = string.Empty;
if (listValue == null)
return toRet;
foreach (T iter in listValue)
{
if (!string.IsNullOrWhiteSpace(iter.Key)) {
toRet = val.Name;
break;
}
}
return toRet;
}
But, the code does not compile. I'm facing the below error.
Severity Code Description Project File Line Suppression State
Error CS1061 'T' does not contain a definition for 'Name' and no accessible extension method 'Name' accepting a first argument of type 'T' could be found (are you missing a using directive or an assembly reference?)
It would be much-appreciated anyone helping on this.
Thank you,
You have said "This code works for every type T" and yet you expect your Type T to have a property called Name, which many many types do not have. Generics do not work that way.
If you want to do something with your instance of type T that requires it to have certain properties, you need to tell the compiler that T is constrained to types that have those properties.
In your case you will need to write an interface common to both of your classes and the add that interface to your generic T definition.
This is well explained (including a good example with code) in the Microsoft documentation here
You have 2 options interface or father class. Bot 2 ways require where T: interfaceName or where T: fatherClassName syntax
For example with interface:
public interface IClass
{
string Key { get; set; }
string Name { get; set; }
string value { get; set; }
}
public class Class1 : IClass
{
public string Key { get; set; }
public string value { get; set; }
public string Name { get; set; }
}
public class Class2 : IClass
{
public string Key { get; set; }
public string value { get; set; }
public string Name { get; set; }
}
Then your generic class would be
private string GetValue<T>(List<T> listValue) where T : IClass
{
string toRet = string.Empty;
if (listValue == null)
return toRet;
foreach (T val in listValue)
{
if (!string.IsNullOrWhiteSpace(val.Key))
{
toRet = val.Name;
break;
}
}
return toRet;
}
You can make it completely generic using Reflection (refer Reflection | PropertyInfo). This way you would be able to handle any classes coming to you. Please refer to the sample code below:
private string GetValue<T>(List<T> listValue)
{
string toRet = string.Empty;
if (listValue == null)
return toRet;
PropertyInfo[] properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
//Since you have mentioned all classes will have "Key" and "Value" and you need to use that only
//To make it completely generic you can maybe get this as input to this function
PropertyInfo keyProperty = properties.FirstOrDefault(x => x.Name.Equals("Key", StringComparison.OrdinalIgnoreCase));
PropertyInfo valueProperty = properties.FirstOrDefault(x => x.Name.Equals("Value", StringComparison.OrdinalIgnoreCase));
if (keyProperty == null || valueProperty == null)
return toRet;
foreach (T iter in listValue)
{
var keyData = keyProperty.GetValue(iter, null);
if (keyData != null && !string.IsNullOrWhiteSpace(keyData.ToString()))
{
toRet = valueProperty.GetValue(iter, null).ToString();
break;
}
}
return toRet;
}
As nvoigt mentioned, in this situation we have to use 'Interface' concept.
Define your classes and interface as below:
public interface IKeyValue
{
public string Key { get; set; }
public string Value { get; set; }
}
public class A : IKeyValue
{
public string Key { get; set; }
public string Value { get; set; }
//other properties...
}
public class B : IKeyValue
{
public string Key { get; set; }
public string Value { get; set; }
//other properties...
}
And your method which is going to use 'Key' and 'Value' should be like this:
private string GetValue<T>(List<T> listValue) where T: IKeyValue
{
string toRet = string.Empty;
if (listValue == null)
return toRet;
foreach (T iter in listValue)
{
if (!string.IsNullOrWhiteSpace(iter.Key))
{
toRet = iter.Value;
break;
}
}
return toRet;
}
'where T: IKeyValue' in method definition means type T is 'IKeyValue' that cause I can access the 'Key' and 'Value' in context (just those that are in IKeyValue interface)
This is how you can use it:
List<IKeyValue> keyValues = new List<IKeyValue>
{new A{Key="a",Value="b"}, new B{Key="x",Value="y"}};
List<A> listA = new List<A>
{ new A { Key = "h", Value = "b" }, new A { Key = "u", Value = "m" } };
List<B> listB = new List<B>
{ new B { Key = "h", Value = "b" }, new B { Key = "u", Value = "m" } };
string resultListInterface = GetValue(keyValues); //valid
string resultListA = GetValue(listA); //valid
string resultListB = GetValue(listB); //valid
For naming convention I change property name from 'value' to 'Value'
I have the following classes domain and Dto classes:
public class Profile
{
public string Name { get; set; }
public string SchoolGrade { get; set; }
}
public class ProfileDTO
{
public string Name { get; set; }
public SchoolGradeDTO SchoolGrade { get; set; }
}
public enum SchoolGradeDTO
{
[Display(Name = "Level One"]
LevelOne,
[Display(Name = "Level Two"]
LevelTwo,
}
I used the following method:
Mapper.CreateMap<Profile, ProfileDTO>()
.ForMember(d => d.SchoolGrade , op => op.MapFrom(o => o.SchoolGrade))
Afterwards, I get the following error:
Requested value 'Level Two' was not found.
How do I map it correctly?
Since you're mapping from the display name and not the enum name you'll need to build a custom mapping function to scan the attributes to find the enum with that display name. You can use ResolveUsing instead of MapFrom to use a custom mapping function:
Mapper.CreateMap<Profile, ProfileDTO>()
.ForMember(d => d.SchoolGrade,
op => op.ResolveUsing(o=> MapGrade(o.SchoolGrade)));
public static SchoolGradeDTO MapGrade(string grade)
{
//TODO: function to map a string to a SchoolGradeDTO
}
You could cache the names in a static dictionary so you don't use reflection every time.
A few methods of doing that can be found here.
Expanding on D Stanley's answer from above in a little more detail, and modified the EnumHelper class from this other discussion to focus on your specific situation as this question really spans two areas, AutoMapper and correctly obtaining an Enum's value from a string.
Enhancing D Stanley's original answer:
public static class QuestionAutoMapperConfig
{
public static void ConfigureAutoMapper()
{
Mapper.CreateMap<Profile, ProfileDTO>()
.ForMember(d => d.SchoolGrade,
op => op.ResolveUsing(o => MapGrade(o.SchoolGrade)));
}
public static SchoolGradeDTO MapGrade(string grade)
{
//TODO: function to map a string to a SchoolGradeDTO
return EnumHelper<SchoolGradeDTO>.Parse(grade);
}
}
I have adjusted the EnumHelper from the mentioned example to quickly show an option where by you could modify the Parse method to first try the standard Enum.Parse(), and failing that to try to do a more detailed comparison of the Enum type by creating a dictionary of the values based either on the enum value name, or it's Display attribute text (if used).
public static class EnumHelper<T>
{
public static IDictionary<string, T> GetValues(bool ignoreCase)
{
var enumValues = new Dictionary<string, T>();
foreach (FieldInfo fi in typeof(T).GetFields(BindingFlags.Static | BindingFlags.Public))
{
string key = fi.Name;
var display = fi.GetCustomAttributes(typeof(DisplayAttribute), false) as DisplayAttribute[];
if (display != null)
key = (display.Length > 0) ? display[0].Name : fi.Name;
if (ignoreCase)
key = key.ToLower();
if (!enumValues.ContainsKey(key))
enumValues[key] = (T)fi.GetRawConstantValue();
}
return enumValues;
}
public static T Parse(string value)
{
T result;
try
{
result = (T)Enum.Parse(typeof(T), value, true);
}
catch (Exception)
{
result = ParseDisplayValues(value, true);
}
return result;
}
private static T ParseDisplayValues(string value, bool ignoreCase)
{
IDictionary<string, T> values = GetValues(ignoreCase);
string key = null;
if (ignoreCase)
key = value.ToLower();
else
key = value;
if (values.ContainsKey(key))
return values[key];
throw new ArgumentException(value);
}
}
in mapping configuration
{
CreateMap<string, CUSTOM_ENUM>().ConvertUsing<StringToEnumConverter<CUSTOM_ENUM>>();
}
converters
public class StringToEnumConverter<T> : ITypeConverter<string, T>, ITypeConverter<string, T?> where T : struct
{
public T Convert(ResolutionContext context)
{
T t;
if (Enum.TryParse(source, out t))
{
return t;
}
var source = (string)context.SourceValue;
if (StringToEnumBase<T>.HasDisplayAttribute())
{
var result = StringToEnumBase<T>.Parse(source);
return result;
}
throw new ConverterException();
}
T? ITypeConverter<string, T?>.Convert(ResolutionContext context)
{
var source = (string)context.SourceValue;
if (source == null) return null;
return Convert(context);
}
}
public static class StringToEnumBase<T> where T:struct
{
public static T Parse(string str)
{
var type = typeof (T);
var enumMembers = type.GetMembers(BindingFlags.Public | BindingFlags.Static);
var enumMembersCollection = enumMembers
.Select(enumMember => new
{
enumMember,
attributes = enumMember.GetCustomAttributes(typeof(DisplayAttribute), false)
})
.Select(t1 => new
{
t1, value = ((DisplayAttribute) t1.attributes[0]).Name
})
.Select(t1 => new Tuple<string, string>(t1.value, t1.t1.enumMember.Name))
.ToList();
var currentMember = enumMembersCollection.FirstOrDefault(item => item.Item1 == str);
if (currentMember == null) throw new ConverterException();
T t;
if (Enum.TryParse(currentMember.Item2, out t))
{
return t;
}
throw new ConverterException();
}
public static bool HasDisplayAttribute()
{
var type = typeof (T);
var attributes = type.GetCustomAttributes(typeof(DisplayAttribute), false);
return attributes.Length > 0;
}
}
Within code I want to do something like this:
item.Stage = Stage.Values.ONE;
Where Stage.Values.ONE represents some predefined Stage:
public class Stage
{
[Key]
public virtual int StageId { get; set; }
public string Name { get; set; }
public TimeSpan Span { get; set; }
}
I'm dealing with EF CodeFirst... and I have a lot of stages to define. I'm not sure if I should store the data in the database, or in the dbContext, or what, but I'm looking for the simplest implementation.
I've tried this:
I've tried the following (defining two constants):
public class Stage
{
[Key]
public virtual int StageId { get; set; }
public string Name { get; set; }
public TimeSpan Span { get; set; }
public static class Values
{
public static readonly Stage ONE = new Stage()
{
StageId = 0,
Name = "ONE",
Span = new TimeSpan(0, 0, 0)
};
public static readonly Stage TWO = new Stage()
{
StageId = 1,
Name = "TWO",
Span = new TimeSpan(0, 0, 10)
};
}
But whenever I create a new instance of an entity that has a Stage, a new Stage is added to the db. I just need a few constant stages.
Use of Stage:
public class Side
{
public Side()
{
Stage = Stage.Values.ONE; // Adds new Stage to DB, when it should be a reference to the one I defined above
}
public virtual Stage Stage { get; set; }
}
It looks a bit like an enum, and I've used a kind of 'extended enum' patter several times before with some success. Because you're refencing these values in code, it may not make sense to store them in the database as well, but it's possible if needed.
The technique is described in detail here: http://lostechies.com/jimmybogard/2008/08/12/enumeration-classes/
Basically, you create a base class which provides a number of services similar to an enum, and then to create your "enumerated class" you inherit from it and provide a bunch of static instances which call the constructor with however many properties you need to have.
To avoid link rot, here is the base class to use (just put the whole class into your project somewhere), and scroll down for your own code.
public abstract class Enumeration : IComparable
{
private readonly int _value;
private readonly string _displayName;
protected Enumeration()
{
}
protected Enumeration(int value, string displayName)
{
_value = value;
_displayName = displayName;
}
public int Value
{
get { return _value; }
}
public string DisplayName
{
get { return _displayName; }
}
public override string ToString()
{
return DisplayName;
}
public static IEnumerable<T> GetAll<T>() where T : Enumeration, new()
{
var type = typeof(T);
var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
foreach (var info in fields)
{
var instance = new T();
var locatedValue = info.GetValue(instance) as T;
if (locatedValue != null)
{
yield return locatedValue;
}
}
}
public override bool Equals(object obj)
{
var otherValue = obj as Enumeration;
if (otherValue == null)
{
return false;
}
var typeMatches = GetType().Equals(obj.GetType());
var valueMatches = _value.Equals(otherValue.Value);
return typeMatches && valueMatches;
}
public override int GetHashCode()
{
return _value.GetHashCode();
}
public static int AbsoluteDifference(Enumeration firstValue, Enumeration secondValue)
{
var absoluteDifference = Math.Abs(firstValue.Value - secondValue.Value);
return absoluteDifference;
}
public static T FromValue<T>(int value) where T : Enumeration, new()
{
var matchingItem = parse<T, int>(value, "value", item => item.Value == value);
return matchingItem;
}
public static T FromDisplayName<T>(string displayName) where T : Enumeration, new()
{
var matchingItem = parse<T, string>(displayName, "display name", item => item.DisplayName == displayName);
return matchingItem;
}
private static T parse<T, K>(K value, string description, Func<T, bool> predicate) where T : Enumeration, new()
{
var matchingItem = GetAll<T>().FirstOrDefault(predicate);
if (matchingItem == null)
{
var message = string.Format("'{0}' is not a valid {1} in {2}", value, description, typeof(T));
throw new ApplicationException(message);
}
return matchingItem;
}
public int CompareTo(object other)
{
return Value.CompareTo(((Enumeration)other).Value);
}
}
And now your code will look something like this:
public class Stage : Enumeration
{
public TimeSpan TimeSpan { get; private set; }
public static readonly Stage One
= new Stage (1, "Stage one", new TimeSpan(5));
public static readonly Stage Two
= new Stage (2, "Stage two", new TimeSpan(10));
public static readonly Stage Three
= new Stage (3, "Stage three", new TimeSpan(15));
private EmployeeType() { }
private EmployeeType(int value, string displayName, TimeSpan span) : base(value, displayName)
{
TimeSpan = span;
}
}
Once you have that set up, you can just store the .Value in the database. I'm afraid I haven't done it in EF, but in nHibernate it's reasonably straight-forward to tell a property to just store the ".Value" of the property, and you can wire it back up when you load the value by having it call:
Stage.FromValue<Stage>(intValue);
Hold the Stage as a property of your entity, use it the way you're doing and add
Ignore(x => x.Stage)
to your mapping. This will ignore this property when mapping to your database.
Edit: I misinterpreted the question.
If you want just the different stages in your database, you should put the stages in their own table with an ID, and refer to that ID trough a relationship. Every entity will hold an additional reference and you'll have to define relationships for them.
Is this what you were looking for?
I am new about attributes. I just try it on my console application.
So how can i validate my person instance below example ?
class Person
{
[StringLength(8,ErrorMessage="Please less then 8 character")]
public string Name { get; set; }
}
Here is simple code example without reflection.
class Program
{
static void Main(string[] args)
{
var invalidPerson = new Person { Name = "Very long name" };
var validPerson = new Person { Name = "1" };
var validator = new Validator<Person>();
Console.WriteLine(validator.Validate(validPerson).Count);
Console.WriteLine(validator.Validate(invalidPerson).Count);
Console.ReadLine();
}
}
public class Person
{
[StringLength(8, ErrorMessage = "Please less then 8 character")]
public string Name { get; set; }
}
public class Validator<T>
{
public IList<ValidationResult> Validate(T entity)
{
var validationResults = new List<ValidationResult>();
var validationContext = new ValidationContext(entity, null, null);
Validator.TryValidateObject(entity, validationContext, validationResults, true);
return validationResults;
}
}
The only function that Attribute can handle is describe, provide some descriptive data with member. They are purely passive and can't contain any logic. (There are some AOP frameworks that can make attributes active). So if you want logic you have to create another class that will read attributes using MemberInfo.GetCustomAttributes and do the validation and return results.
Below code shows how to determine validation for only properties and give idea validation for methods ,classes etc.
public class DataValidator
{
public class ErrorInfo
{
public ErrorInfo(string property, string message)
{
this.Property = property;
this.Message = message;
}
public string Message;
public string Property;
}
public static IEnumerable<ErrorInfo> Validate(object instance)
{
return from prop in instance.GetType().GetProperties()
from attribute in prop.GetCustomAttributes(typeof(ValidationAttribute), true).OfType<ValidationAttribute>()
where !attribute.IsValid(prop.GetValue(instance, null))
select new ErrorInfo(prop.Name, attribute.FormatErrorMessage(string.Empty));
}
}
After adding this code to project we can use it like:
var errors =DataValidator.Validate(person);
foreach (var item in errors)
{
Console.WriteLine(item.Property +" " + item.Message);
}