I want to use Data annotations Range attribute inside my mvc viewmodel. Problem is that this range attributes should be dynamic values.
My viewmodel has also ValueOne and ValueTwo properties. Based on this values I want to set Range attr. values like
[Range(1, 1000, ErrorMessage = "Value for {0} must be between {1} and {2}.")]
Where 1 and 1000 should be replaces with ValueOne and ValueTwo property values.
so I tried with custom ValidateCustomAttribute
public class ValidateCustomAttribute: ValidationAttribute
{
private readonly double _MinValue = 0;
private readonly double _MaxValue = 100;
public override bool IsValid(object value)
{
double val = (double)value;
return val >= _MinValue && val <= _MaxValue;
}
public override string FormatErrorMessage(string name)
{
return string.Format(ErrorMessage, _MinValue, _MaxValue);
}
}
how can I replace this
private readonly double _MinValue = 0;
private readonly double _MaxValue = 100;
with dynamic values (ValueOne and ValueTwo from my viewmodel).
This can't be done, you can't have variables in attributes. Attribute values must be known at compile time.
See this question/answer and this one.
Just add a constructor:
private double _MinValue, _MaxValue; // no readonly keyword
public ValidateCustomAttribute(double min, double max, Func<string> errorMessageAccessor)
: base(errorMessageAccessor)
{
_MinValue = min;
_MaxValue = max;
}
What you can't do is have variables in the attribute constructor invokation.
This is not possible:
[ValidateCustom(min, max)]
But if you use literals (or constants) in your code you can have these:
[ValidateCustom(1, 1000)]
And on another class or method:
[ValidateCustom(3, 45)]
What you are missing is the constructor taking in those static values and affixing them to the construct you are describing with your attribute.
EDIT: The ugly way around this
If you really really need this, you can circumvent the limitation but it is as ugly as it can get. I am STRONGLY against this, but you asked for it...
categorize your data
map categories to binding symbols
use binding symbols
resolve binding symbols to data
So, let's get to work:
1) categorize your data
Say, your data is a range (min, max), the first thing to do is establish which values are possible, let's say you have 4 possible ranges (may be hundreds, but that's anther problem altogether).
(1, 1000)
(10, 20)
(3, 45)
(5, 7)
2) map categories to binding symbols
Now you have to use an enum as binding symbols for those ranges:
public enum MyRanges
{
R1, R2, R3, R4
}
3) use binding symbols
Define the constructor as taking in the binding symbol:
private MyRanges _R;
public ValidateCustomAttribute(MyRanges r, Func<string> errorMessageAccessor)
: base(errorMessageAccessor)
{
_R = r;
}
The attribute will be used like this:
[ValidateCustom(MyRanges.R2, "ERROR!")]
4) resolve binding symbols to data
The last you need is a dictionary with the actual data:
Dictionary<MyRanges, double> dataMin = {
{ MyRanges.R1, 1},
{ MyRanges.R2, 10},
{ MyRanges.R3, 3},
{ MyRanges.R4, 5}
};
Dictionary<MyRanges, double> dataMax = {
{ MyRanges.R1, 1000},
{ MyRanges.R2, 20},
{ MyRanges.R3, 45},
{ MyRanges.R4, 7}
};
The test will use the binding this way:
public override bool IsValid(object value)
{
double val = (double)value;
return val >= dataMin[_R] && val <= dataMax[_R]; // get data through binding
}
Now you can change behind the scenes those values and all attributes bound by the binding symbols behave differently:
dataMax[MyRanges.R4] = 29;
Done.
What cannot change is now the binding from attribute to category, but the data contained in the category is free to change.
But ugly and impossible to maintain. Don't do it, really.
You can do it like this:
public class MinimumAgeAttribute : RangeAttribute
{
public static string MinimumValue => ConfigurationManager.AppSettings["your key"];
public static string MaxValue => ConfigurationManager.AppSettings["your key"];
public CustomRangeAttribute(Type type):base(type,MaxValue , MinimumValue)
{
}
}
And after this you have to register the attribute in Global.asax like this:
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(CustomRangeAttribute),
typeof(RangeAttributeAdapter));
After this you can use it like this:
[CustomRange(typeof(DateTime), ErrorMessage = "You message")]
public DateTime DateOfBirth { get; set; }
Related
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.
I'm parsing a CSV file and placing the data in a struct. I'm using the TextFieldParser from this question and it's working like a charm except that it returns a String[]. Currently I have the ugly process of:
String[] row = parser.ReadFields();
DispatchCall call = new DispatchCall();
if (!int.TryParse(row[0], out call.AccountID)) {
Console.WriteLine("Invalid Row: " + parser.LineNumber);
continue;
}
call.WorkOrder = row[1];
call.Description = row[2];
call.Date = row[3];
call.RequestedDate = row[4];
call.EstStartDate = row[5];
call.CustomerID = row[6];
call.CustomerName = row[7];
call.Caller = row[8];
call.EquipmentID = row[9];
call.Item = row[10];
call.TerritoryDesc = row[11];
call.Technician = row[12];
call.BillCode = row[13];
call.CallType = row[14];
call.Priority = row[15];
call.Status = row[16];
call.Comment = row[17];
call.Street = row[18];
call.City = row[19];
call.State = row[20];
call.Zip = row[21];
call.EquipRemarks = row[22];
call.Contact = row[23];
call.ContactPhone = row[24];
call.Lat = row[25];
call.Lon = row[26];
call.FlagColor = row[27];
call.TextColor = row[28];
call.MarkerName = row[29];
The struct consists of all those fields being Strings except for AccountID being an int. It annoys me that they're not strongly typed, but let's over look that for now. Given that parser.ReadFields() returns a String[] is there a more efficient way to fill a struct (possibly converting some values such as row[0] needing to become an int) with the values in the array?
**EDIT:**One restriction I forgot to mention that may impact what kind of solutions will work is that this struct is [Serializable] and will be sent Tcp somewhere else.
Your mileage may vary on whether it is a better solution, but you could use reflection and define an Attribute class that you use to mark your struct members with. The attribute would take the array index as an argument. Assigning the value from the right array element would then happen by using reflection.
You could define your attribute like this:
[AttributeUsage(AttributeTargets.Property)]
public sealed class ArrayStructFieldAttribute : Attribute
{
public ArrayStructFieldAttribute(int index)
{
this.index = index;
}
private readonly int index;
public int Index {
get {
return index;
}
}
}
This means the attribute can simply be used to associate an int value named Index with a property.
Then, you could mark your properties in the struct with that attribute (just some exemplary lines):
[ArrayStructField(1)]
public string WorkOrder { // ...
[ArrayStructField(19)]
public string City { // ...
The values could then be set with the Type object for your struct type (you can obtain it with the typeof operator):
foreach (PropertyInfo prop in structType.GetProperties()) {
ArrayStructFieldAttribute attr = prop.GetCustomAttributes(typeof(ArrayStructFieldAttribute), false).Cast<ArrayStructFieldAttribute>().FirstOrDefault();
if (attr != null) {
// we have found a property that you want to load from an array element!
if (prop.PropertyType == typeof(string)) {
// the property is a string property, no conversion required
prop.SetValue(boxedStruct, row[attr.Index]);
} else if (prop.PropertyType == typeof(int)) {
// the property is an int property, conversion required
int value;
if (!int.TryParse(row[attr.Index], out value)) {
Console.WriteLine("Invalid Row: " + parser.LineNumber);
} else {
prop.SetValue(boxedStruct, value);
}
}
}
}
This code iterates over all properties of your struct type. For each property, it checks for our custom attribute type defined above. If such an attribute is present, and if the property type is string or int, the value is copied from the respective array index.
I am checking for string and int properties as that's the two data types you mentioned in your question. even though you have only one particular index that contains an int value now, it's good for maintainability if this code is prepared to handle any index as a string or an int property.
Note that for a greater number of types to handle, I'd suggest not using a chain of if and else if, but rather a Dictionary<Type, Func<string, object>> that maps property types to conversion functions.
If you want to create something very flexible you can mark each property on DispatchCall using a custom attribute. Something like this:
class DispatchCall {
[CsvColumn(0)]
public Int32 AccountId { get; set; }
[CsvColumn(1)]
public String WorkOrder { get; set; }
[CsvColumn(3, Format = "yyyy-MM-dd")]
public DateTime Date { get; set; }
}
This allows you to associate each property with a column. For each row you can then iterate over all properties and by using the attribute you can assign the right value to the right property. You will have to do some type conversion from string to numbers, dates and perhaps enums. You can add extra properties to the attribute to assist you in that process. In the example I invented Format which should be used when a DateTime is parsed:
Object ParseValue(String value, TargetType targetType, String format) {
if (targetType == typeof(String))
return value;
if (targetType == typeof(Int32))
return Int32.Parse(value);
if (targetType == typeof(DateTime))
DateTime.ParseExact(value, format, CultureInfo.InvariantCulture);
...
}
Using TryParse methods in the above code can improve the error handling by allowing you to provide more context when an unparsable value is encountered.
Unfortunately, this approach is not very efficient because the reflection code will be executed for each row in your input file. If you want to make this more efficient you need to dynamically create a compiled method by reflecting once over DispatchCall that you then can apply on each row. It is possible but not particular easy.
How dependent are you on the library that you're using? I've found File Helpers to be quite useful for this sort of thing. Your code would look something like:
using FileHelpers;
// ...
[DelimitedRecord(",")]
class DispatchCall {
// Just make sure these are in order
public int AccountID { get; set; }
public string WorkOrder { get; set; }
public string Description { get; set; }
// ...
}
// And then to call the code
var engine = new FileHelperEngine(typeof(DispatchCall));
engine.Options.IgnoreFirstLines = 1; // If you have a header row
DispatchCall[] data = engine.ReadFile(FileName) as DispatchCall[];
You now have a DispatchCall array, and the engine did all the heavy lifting for you.
Use reflection as #Grozz suggested in the comment. Mark each property of the struct class with an attribute (ie [ColumnOrdinal] ) and then use this to map the information with the proper column. If you have double, decimal and so on as a target, you should also consider using Convert.ChangeType to proper convert in the target type. if you are not happy with the performances, you can enjoy create a DynamicMethod on the fly, more challenging, but really performant and beautiful. The challenge is to write the IL instruction in memory to do the "plumbing" you did by hand ( I usually create some example code, and then look inside it with IL spy as a starting point ). of course you will cache somewhere such dynamic methods so creating them is requested just once.
The first thing that comes to mind is to use reflection to iterate over the properties and match them up to the elements in the string[] based on an attribute value.
public struct DispatchCall
{
[MyAttribute(CsvIndex = 1)]
public string WorkOrder { get; set; }
}
MyAttribute would just be a custom attribute with an index that would match up to the field position in the CSV.
var row = parser.ReadFields();
for each property that has MyAttribute...
var indexAttrib = MyAttribute attached to property
property.Value = row[indexAttrib.Index]
next
(Pseudocode, obviously)
or
[StructLayout(LayoutKind.Sequential)] // keep fields in order
public strict DispatchCall
{
public string WorkOrder;
public string Description;
}
StructLayout will keep the struct fields in order, so you can iterate over them without having to explicitly specify a column number for each field. That can save some maintenance if you have a lot of fields.
Or, you could skip the process entirely, and store the field names in a dictionary:
var index = new Dictionary<int, string>();
/// populate index with row index : field name values, preferable from some sort of config file or database
index[0] = "WorkOrder";
index[1] = "Description";
...
var values = new Dictionary<string,object>();
for(var i=0;i<row.Length;i++)
{
values.Add(index[i],row[i]);
}
That's easier to load, but doesn't really take advantage of strong typing, which makes this less than ideal.
You could also generate a dynamic method or a T4 template. You could generate code from a mapping file in the format
0,WorkOrder
1,Description
...
load that, and generate a method that looks like this:
/// emit this
call.WorkOrder = row[0];
call.Description = row[1];
etc.
That approach is used in a few micro-ORMs floating around and seems to work pretty well.
Ideally, your CSV would include a row with field names that would make this a lot easier.
OR, yet another approach, use StructLayout along with a dynamic method to avoid having to keep a field:column_index mapping aside from the struct itself.
OR, create an enum
public enum FieldIndex
{
WorkOrder=0
,
Description // only have to specify explicit value for the first item in the enum
, /// ....
,
MAX /// useful for getting the maximum enum integer value
}
for(var i=0;i<FieldIndex.MAX;i++)
{
var fieldName = ((FieldIndex)i).ToString(); /// get string enum name
var value = row[i];
// use reflection to find the property/field FIELDNAME, and set it's value to VALUE.
}
if you are going for speed you could a brittle switch statement.
var columns = parser.ReadFields();
for (var i = 0; i < columns.Length; i++)
{
SetValue(call, i, columns[i]);
}
private static void SetValue(DispatchCall call, int column, string value)
{
switch column
{
case 0:
SetValue(ref call.AccountId, (value) => int.Parse, value);
return;
case 1:
SetValue(ref call.WorkOrder, (value) => value, value);
return;
...
default:
throw new UnexpectedColumnException();
}
}
private static void SetValue<T>(
ref T property,
Func<string, T> setter
value string)
{
property = setter(value);
}
Its a shame that TextFieldParser does not allow you to read one field at a time, then you could avoid building and indexing the columns array.
i have recently stumbled upon a project(8-puzzle solver using A* alg) in which some codes are weird to me , because i have never seen the likes of it before .
what does this line mean ? what is this ?!
this[StateIndex]
whats this notation ? i cant undersand it at all !
i posted a sample of the class so that you can see it almost all together .
and one more question , is it not wrong to have a class implemented like StateNode? it used only a constructor to initialize its fields , and yet worst, declared them all public ! should he/she not have implemented Propertise for this task?
public enum Direction
{
Up = 1, Down = 2, Left = 3, Right = 4, UpUp = 5, DownDown = 6, LeftLeft = 7, RightRight = 8, Stop = 9
}
class StateNode
{
public int Parent;
public List<int> Childs;
public Direction Move;
public Direction ParentMove;
public byte[,] State;
public byte Depth;
public byte NullRow;
public byte NullCol;
public StateNode()
{ }
public StateNode(int NewParent, Direction NewMove, Direction ParentMove, byte NewDepth, byte NewNullRow, byte NewNullCol)
{
this.Parent = NewParent;
this.State = new byte[5, 5];
this.Move = NewMove;
this.ParentMove = ParentMove;
this.Depth = NewDepth;
this.NullRow = NewNullRow;
this.NullCol = NewNullCol;
this.Childs = new List<int>();
}
}
class StateTree : List<StateNode>
{
public static long MakedNodes;
public static long CheckedNodes;
public static byte MaxDepth;
public List<int> Successor1(int StateIndex)
{
List<int> RetNodes = new List<int>();
StateNode NewState = new StateNode();
//Up
if (this[StateIndex].NullRow + 1 <= 3 && this[StateIndex].ParentMove != Direction.Up)
{
NewState = ChangeItemState(this[StateIndex], StateIndex, Direction.Up, Direction.Down, Convert.ToByte(this[StateIndex].Depth + 1), this[StateIndex].NullRow, this[StateIndex].NullCol, Convert.ToByte(this[StateIndex].NullRow + 1), this[StateIndex].NullCol);
this.Add(NewState);
RetNodes.Add(this.Count - 1);
StateTree.MakedNodes++;
this[StateIndex].Childs.Add(this.Count - 1);
if (NewState.Depth > StateTree.MaxDepth)
StateTree.MaxDepth = NewState.Depth;
}
//Down
//Left
//Right
return RetNodes;
}
}
In your concrete case it's just access to the element, as it used inside the class that is derived from the List<T>
But it can be also indexer which enables index acces to your class object.
For example declare class like this:
public class ListWrapper
{
private List<int> list = ...
public int this[int index]
{
return list[index];
}
}
and after use it like
var lw = new ListWrapper();
//fill it with data
int a = lw[2]; //ACCESS WITH INDEX EVEN IF THE TYPE IS NOT COLLECTION BY ITSELF
this[StateIndex] is using the current class' indexer property. The indexer property is what allows you to access an element in a collection or list object as if it was an array. For instance:
List<string> strings = new List<string>();
strings.Add("Item 1");
strings.Add("Item 2");
strings.Add("Item 3");
string x = strings[0]; // Returns the first item in the list ("Item 1")
When you want to access the indexer property of your own class, however, you have to preface it with the this keyword. You'll notice that in your example, the StateTree class doesn't implement an indexer property, so that may be adding to your confusion. The reason it works is because StateTree inherits from List<StateNode> which does implement an indexer property.
But don't get confused between classes with indexer properties and arrays. Arrays are a completely different thing, though the syntax is similar. An array is a list of objects which can be accessed by an index. An indexer property is an unnamed property of a single object that acts as an array. So for instance, List<string> has an indexer property, so you can access the items it contains using the same syntax as an array index (as shown in the above example). However, you can still make an array of List<string> objects. So for instance:
List<string> strings1 = new List<string>();
strings1.Add("Item 1.1");
strings1.Add("Item 1.2");
List<string> strings2 = new List<string>();
strings2.Add("Item 2.1");
strings2.Add("Item 2.2");
List<string>[] stringsArray = new List<string>[] { strings1, strings2 };
object result;
result = stringsArray[0]; // Returns strings1
result = stringsArray[0][1]; // Returns "Item 1.2"
result = stringsArray[1][0]; // Returns "Item 2.1"
As far as StateNode goes, there's nothing technically wrong with it, and it's not unusual to have a constructor that initializes all the field values, but it's always better to use properties instead of public fields.
its Indexed Properties in C# .net .
you can check Tutorial : http://msdn.microsoft.com/en-us/library/aa288464(v=vs.71).aspx check here
this[StateIndex] is pointing to an element within the class. Because StateTree inherits from a List<T>, you have a collection that's accessible by index (in this case this[N] where N is the element's index.
this[StateIndex] is how you give a class and indexed property e.g
public class IndexedClass
{
private List<String> _content;
public IndexedClass()
{
_content = new List<String>();
}
public Add(String argValue)
{
_content.Add(argValue);
}
public string this[int index]
{
get
{
return _content[index];
}
set
{
_content[Index] = value;
}
}
}
so now you can do
IndexedClass myIndex = new IndexedClass();
myIndex.Add("Fred");
Console.Writeline(myIndex[0]);
myIndex[0] = "Bill";
Console.Writeline(myIndex[0]);
As for statenode if it's local to the class (a helper) then you could argue it as okay, I don't like it though, another ten minutes work it could be done properly. If it's public in the assembly, then it's not accpetable in my opinion. But that is an opinion.
This is related to a prior question of mine C# Generic List conversion to Class implementing List<T>
I have the following code:
public abstract class DataField
{
public string Name { get; set; }
}
public class DataField<T> : DataField
{
public T Value { get; set; }
}
public static List<DataField> ConvertXML(XMLDocument data) {
result = (from d in XDocument.Parse(data.OuterXML).Root.Decendendants()
select new DataField<string>
{
Name = d.Name.ToString(),
Value = d.Value
}).Cast<DataField>().ToList();
return result;
}
This works however I would like to be able to modify the select portion of the LINQ query to be something like this:
select new DataField<[type defined in attribute of XML Element]>
{
Name = d.Name.ToString(),
Value = d.Value
}
Is this just a poor approach? is it possible? Any suggestions?
Here is a working solution: (You must specify fully qualified type names for your Type attribute otherwise you have to configure a mapping somehow...)
I used the dynamic keyword, you can use reflection to set the value instead if you do not have C# 4...
public static void Test()
{
string xmlData = "<root><Name1 Type=\"System.String\">Value1</Name1><Name2 Type=\"System.Int32\">324</Name2></root>";
List<DataField> dataFieldList = DataField.ConvertXML(xmlData);
Debug.Assert(dataFieldList.Count == 2);
Debug.Assert(dataFieldList[0].GetType() == typeof(DataField<string>));
Debug.Assert(dataFieldList[1].GetType() == typeof(DataField<int>));
}
public abstract class DataField
{
public string Name { get; set; }
/// <summary>
/// Instanciate a generic DataField<T> given an XElement
/// </summary>
public static DataField CreateDataField(XElement element)
{
//Determine the type of element we deal with
string elementTypeName = element.Attribute("Type").Value;
Type elementType = Type.GetType(elementTypeName);
//Instanciate a new Generic element of type: DataField<T>
dynamic dataField = Activator.CreateInstance(typeof(DataField<>).MakeGenericType(elementType));
dataField.Name = element.Name.ToString();
//Convert the inner value to the target element type
dynamic value = Convert.ChangeType(element.Value, elementType);
//Set the value into DataField
dataField.Value = value;
return dataField;
}
/// <summary>
/// Take all the descendant of the root node and creates a DataField for each
/// </summary>
public static List<DataField> ConvertXML(string xmlData)
{
var result = (from d in XDocument.Parse(xmlData).Root.DescendantNodes().OfType<XElement>()
select CreateDataField(d)).ToList();
return result;
}
}
public class DataField<T> : DataField
{
public T Value { get; set; }
}
You cannot do this easily in C#. The generic type argument has to specified at compile time. You can use reflection to do otherwise
int X = 1;
Type listype = typeof(List<>);
Type constructed = listype.MakeGenericType( X.GetType() );
object runtimeList = Activator.CreateInstance(constructed);
Here we have just created a List<int>. You can do it with your type
Different instances of a generic class are actually different classes.
I.e. DataField<string> and DataField<int> are not the same class at all(!)
This means, that you can not define the generic parameter during run-time, as it has to be determined during compile-time.
I would say this is a poor approach. In reality, even after you parse your XML file, you're not going to know what types of "DataFields" you have. You might as well just parse them as objects.
However, if you know that you're only ever going to have x number of types, you can do like so:
var Dictionary<string, Func<string, string, DataField>> myFactoryMaps =
{
{"Type1", (name, value) => { return new DataField<Type1>(name, Type1.Parse(value); } },
{"Type2", (name, value) => { return new DataField<Type2>(name, Type2.Parse(value); } },
};
Termit's answer is certainly excellent. Here is a little variant.
public abstract class DataField
{
public string Name { get; set; }
}
public class DataField<T> : DataField
{
public T Value { get; set; }
public Type GenericType { get { return this.Value.GetType(); } }
}
static Func<XElement , DataField> dfSelector = new Func<XElement , DataField>( e =>
{
string strType = e.Attribute( "type" ).Value;
//if you dont have an attribute type, you could call an extension method to figure out the type (with regex patterns)
//that would only work for struct
Type type = Type.GetType( strType );
dynamic df = Activator.CreateInstance( typeof( DataField<>).MakeGenericType( type ) );
df.Name = e.Attribute( "name" ).Value;
dynamic value = Convert.ChangeType( e.Value , type );
df.Value = value;
return df;
} );
public static List<DataField> ConvertXML( string xmlstring )
{
var result = XDocument.Parse( xmlstring )
.Root.Descendants("object")
.Select( dfSelector )
.ToList();
return result;
}
static void Main( string[] args )
{
string xml = "<root><object name=\"im1\" type=\"System.String\">HelloWorld!</object><object name=\"im2\" type=\"System.Int32\">324</object></root>";
List<DataField> dfs = ConvertXML( xml );
}
you can create generic type by reflection
var instance = Activator.CreateInstance( typeof(DataField)
.MakeGenericType(Type.GetType(typeNameFromAttribute) );
// and here set properties also by reflection
#Termit and #Burnzy put forward good solutions involving factory methods.
The problem with that is that you're loading up your parsing routine with a bunch of extra logic (more testing, more errors) for dubious returns.
Another way to do it would be to use a simplified string-based DataField with typed read methods - the top answer for this question.
An implementation of a typed-value method that would be nice but only works for value types (which does not include strings but does include DateTimes):
public T? TypedValue<T>()
where T : struct
{
try { return (T?) Convert.ChangeType(this.Value, typeof(T)); }
catch { return null; }
}
I'm assuming that you're wanting to use the type information to do things like dynamically assigning user-controls to the field, validation rules, correct SQL types for persistence etc.
I've done a lot of this sort of thing with approaches that seem a bit like yours.
At the end of the day you should seperate your metadata from your code - #Burnzy's answer chooses the code based on the metadata (a "type" attribute of the DataField element) and is a very simple example of this.
If you're dealing with XML, XSDs are a very useful and extensible form of metadata.
As far as what you store each field's data in - use strings because:
they are nullable
they can store partial values
they can store invalid values (makes telling the user to sort their act out more transparent)
they can store lists
special cases won't invade unrelated code because there aren't any
learn regular expressions, validate, be happy
you can convert them to stronger types really easily
I found it very rewarding to develop little frameworks like this - it is a learning experience and you'll come out understanding a lot more about UX and the reality of modelling from it.
There are four groups of test cases that I would advise you to tackle first:
Dates, Times, Timestamps (what I call DateTime), Periods (Timespan)
in particular, make sure you test having a different server locality from the client's.
lists - multi-select foreign keys etc
null values
invalid input - this generally involves retaining the original value
Using strings simplifies all this greatly because it allows you to clearly demarcate responsibilities within your framework. Think about doing fields containing lists in your generic model - it gets hairy rather quickly and it is easy to end up with a special case for lists in pretty much every method. With strings, the buck stops there.
Finally, if you want a solid implementation of this sort of stuff without having to do anything much, consider DataSets - old school I know - they do all sorts of wonderful things you wouldn't expect but you do have to RTFM.
The main downfall of that idea would be that it isn't compatible with WPF data binding - though my experience has been that reality isn't compatible with WPF data binding.
I hope I interpreted your intentions correctly - good luck either way :)
Unfortunately, there no inheritance relation between C<T> and C<string> for instance.
However, you can inherit from a common non-generic class and in addition to this implement a generic interface.
Here I use explicit interface implementation in order to be able to declare a Value property typed as object, as well as a more specifically typed Value property.
The Values are read-only and can only be assigned through a typed constructor parameter. My construction is not perfect, but type safe and doesn't use reflection.
public interface IValue<T>
{
T Value { get; }
}
public abstract class DataField
{
public DataField(string name, object value)
{
Name = name;
Value = value;
}
public string Name { get; private set; }
public object Value { get; private set; }
}
public class StringDataField : DataField, IValue<string>
{
public StringDataField(string name, string value)
: base(name, value)
{
}
string IValue<string>.Value
{
get { return (string)Value; }
}
}
public class IntDataField : DataField, IValue<int>
{
public IntDataField(string name, int value)
: base(name, value)
{
}
int IValue<int>.Value
{
get { return (int)Value; }
}
}
The list can then be declared with the abstract base class DataField as generic parameter:
var list = new List<DataField>();
switch (fieldType) {
case "string":
list.Add(new StringDataField("Item", "Apple"));
break;
case "int":
list.Add(new IntDataField("Count", 12));
break;
}
Access the strongly typed field through the interface:
public void ProcessDataField(DataField field)
{
var stringField = field as IValue<string>;
if (stringField != null) {
string s = stringField.Value;
}
}
While the other questions mostly proposed an elegant solution to convert your XML elements to a generic class instance, I'm going to deal with the consequences of taking the approach to model the DataField class as a generic like DataField<[type defined in attribute of XML Element]>.
After selecting your DataField instance into the list you want to use these fields. Her polymorphism comes into play! You want to iterate your DataFields an treat them in a uniform way. Solutions that use generics often end up in a weird switch/if orgy since there is no easy way to associate behavior based on the generic type in c#.
You might have seen code like this (I'm trying to calculate the sum of all numeric DataField instances)
var list = new List<DataField>()
{
new DataField<int>() {Name = "int", Value = 2},
new DataField<string>() {Name = "string", Value = "stringValue"},
new DataField<float>() {Name = "string", Value = 2f},
};
var sum = 0.0;
foreach (var dataField in list)
{
if (dataField.GetType().IsGenericType)
{
if (dataField.GetType().GetGenericArguments()[0] == typeof(int))
{
sum += ((DataField<int>) dataField).Value;
}
else if (dataField.GetType().GetGenericArguments()[0] == typeof(float))
{
sum += ((DataField<float>)dataField).Value;
}
// ..
}
}
This code is a complete mess!
Let's go try the polymorphic implementation with your generic type DataField and add some method Sum to it that accepts the old some and returns the (possibly modified) new sum:
public class DataField<T> : DataField
{
public T Value { get; set; }
public override double Sum(double sum)
{
if (typeof(T) == typeof(int))
{
return sum + (int)Value; // Cannot really cast here!
}
else if (typeof(T) == typeof(float))
{
return sum + (float)Value; // Cannot really cast here!
}
// ...
return sum;
}
}
You can imagine that your iteration code gets a lot clearer now but you still have this weird switch/if statement in you code. And here comes the point: Generics do not help you here it's the wrong tool at the wrong place. Generics are designed in C# for giving you compile time type safety to avoid potential unsafe cast operations. They additionally add to code readability but that's not the case here :)
Let's take a look at the polymorphic solution:
public abstract class DataField
{
public string Name { get; set; }
public object Value { get; set; }
public abstract double Sum(double sum);
}
public class IntDataField : DataField
{
public override double Sum(double sum)
{
return (int)Value + sum;
}
}
public class FloatDataField : DataField
{
public override double Sum(double sum)
{
return (float)Value + sum;
}
}
I guess you will not need too much fantasy to imagine how much adds to your code's readability/quality.
The last point is how to create instances of these classes. Simply by using some convention TypeName + "DataField" and Activator:
Activator.CreateInstance("assemblyName", typeName);
Short Version:
Generics is not the appropriate approach for your problem because it does not add value to the handling of DataField instances. With the polymorphic approach you can work easily with the instances of DataField!
It's not impossible as you can do this with reflection. But this isn't what generics were designed for and isn't how it should be done. If you're going to use reflection to make the generic type, you may as well not use a generic type at all and just use the following class:
public class DataField
{
public string Name { get; set; }
public object Value { get; set; }
}
You'll need to insert the logic for determining the data type from your XML and add all the types you need to use but this should work:
result = (from d in XDocument.Parse(data.OuterXML).Root.Descendants()
let isString = true //Replace true with your logic to determine if it is a string.
let isInt = false //Replace false with your logic to determine if it is an integer.
let stringValue = isString ? (DataField)new DataField<string>
{
Name = d.Name.ToString(),
Value = d.Value
} : null
let intValue = isInt ? (DataField)new DataField<int>
{
Name = d.Name.ToString(),
Value = Int32.Parse(d.Value)
} : null
select stringValue ?? intValue).ToList();
I want to store data such as
{
{"apple",15 }
{"pear",12.5 }
{"", 10 }
{"", 0.45 }
}
Data will be plotted on a bar chart (string will be the legend and double will be the value)
Insert order is important.
Perfs don't matter.
Strings could be duplicated or empty. (values could be duplicated too)
I need to get min and max values (easily if possible) to set the scale.
I use
List<KeyValuePair<string, double>> data = new List<KeyValuePair<string, double>>();
data.Add(new KeyValuePair<string,double>("",i));
Quite boring and unreadable.
Is there a cleaner way to do it ?
StringDoubleCollection data = new StringDoubleCollection();
data.add("apple",15);
data.add("",10);
double max = data.values.Max();
double min = data.values.Min();
if not how to get the max value of List<KeyValuePair<string, double>> without too much hassle
NameValueCollection looks nice but its a <string,string> I need a <string,double>
You could create a class like the following:
class X
{
public string Name { get; set; }
public double Value { get; set; }
// name is an optional parameter (this means it can be used only in C# 4)
public X(double value, string name = "")
{
this.Name = name;
this.Value = value;
}
// whatever
}
And then get maximum and minimum values using LINQ with a selector:
var data = new List<X>();
data.Add(new X(35.0, "Apple"))
data.Add(new X(50.0));
double max = data.Max(a => a.Value);
double min = data.Min(a => a.Value);
EDIT: if the code above still seems unreadable to you try to improve it using an operator for cases in which you want to have just the value.
// Inside X class...
public static implicit operator X(double d)
{
return new X(d);
}
// Somewhere else...
data.Add(50.0);
To determine which data structure you really want, lets look at your usage patterns.
Insert order matters.
You don't access your items by key.
You want min and max.
A heap offers min or max, but doesn't preserve order. A hash based dictionary also doesn't preserve order. A List is actually a good choice for your data structure. It is available and offers excellent support.
You can prettify your code by defining classes for both the data structure and your bar data. And you can add min/max functionality to the collection. Note: I didn't use the Linq Min/Max functions, because they return the minimum value, not the minimum element.
public class BarGraphData {
public string Legend { get; set; }
public double Value { get; set; }
}
public class BarGraphDataCollection : List<BarGraphData> {
// add necessary constructors, if any
public BarGraphData Min() {
BarGraphData min = null;
// finds the minmum item
// prefers the item with the lowest index
foreach (BarGraphData item in this) {
if ( min == null )
min = item;
else if ( item.Value < min.Value )
min = item;
}
if ( min == null )
throw new InvalidOperationException("The list is empty.");
return min;
}
public BarGraphData Max() {
// similar implementation as Min
}
}
Have you looked at LookUp?
The only problem is that it's immutable, so you need to be able to create your collection in one go.
As Anthony Pegram notes, it's a bit of a pain to create one. It depends on where your data is coming from. Have a look at the ToLookup method.
If it's worth it for usability (i.e. you're using awkward collections of List<KeyValuePair<string, double>> everywhere, it might just be worth it to implement StringDoubleCollection. It wouldn't be that difficult to wrap the underlying collection with the friendlier syntax you've described in your example.
And, as other comments / answers are suggesting, the Framework doesn't seem to provide a simpler solution that matches all of your requirements...
As for "max value", I assume you mean the Key-Value Pair with the greatest value. It can be retrieved like so:
var max = list.Select(kvp => kvp.Value).Max();
Just define your own model class to hold the data instead of depending on a KeyValuePair and everything becomes cleaner:
using System;
using System.Collections.Generic;
public class Fruit
{
public string Name {get; set;}
public double Price {get; set;}
}
public class Program
{
public static void Main()
{
List<Fruit> _myFruit = new List<Fruit>();
_myFruit.Add(new Fruit{Name="apple", Price=15 });
_myFruit.Add(new Fruit{Name="pear", Price=12.5 });
_myFruit.Add(new Fruit{Name="", Price=10 });
_myFruit.Add(new Fruit{Name="", Price=0.45 });
// etc...
}
}
What about implementing the StringDoubleCollection to work like you want...
public class StringDoubleCollection
{
private List<KeyValuePair<string, double>> myValues;
public List<double> values
{
get { return myValues.Select(keyValuePair => keyValuePair.Value).ToList(); }
}
public void add(string key, double value)
{
myValues.Add(new KeyValuePair<string,double>(key,value));
}
}
You can implementing Dictionary<key, value>
Dictionary<string, string> openWith = new Dictionary<string, string>();
openWith.Add("txt", "notepad.exe");
openWith.Add("bmp", "paint.exe");
openWith.Add("dib", "paint.exe");
openWith.Add("rtf", "wordpad.exe");
https://learn.microsoft.com/pt-br/dotnet/api/system.collections.generic.dictionary-2?view=net-5.0