C# User Defined CSV Mapping to POCO - c#

I have a system that reads input data from a Serial/UDP/TCP source. The input data is simply a CSV of different datattypes (e.g. DateTime, double, int, string). An example string might be:
2012/03/23 12:00:00,1.000,23,information,1.234
I currently have (untested) code that allows the user to specify which value in the CSV list goes to which property of a POCO.
So in the above example, i would have a object like so:
public class InputData
{
public DateTime Timestamp{get;set;}
public double Distance{get;set;}
public int Metres{get;set;}
public string Description{get;set;}
public double Height{get;set;}
}
Now in this class, i have a method to parse a CSV string and populate the properties. This method also requires "Mapping" information, as there is no guarantee which order the CSV data will arrive in - it is up to the user to define the correct order.
This is my Mapping class:
//This general class handles mapping CSV to objects
public class CSVMapping
{
//A dictionary holding Property Names (Key) and CSV indexes (Value)
//0 Based index
public IDictionary<string, int> Mapping { get; set; }
}
Now my method ParseCSV():
//use reflection to parse the CSV survey input
public bool ParseCSV(string pCSV, CSVMapping pMapping)
{
if (pMapping == null) return false;
else
{
Type t = this.GetType();
IList<PropertyInfo> properties = t.GetProperties();
//Split the CSV values
string[] values = pCSV.Split(new char[1] { ',' });
//for each property set its value from the CSV
foreach (PropertyInfo prop in properties)
{
if (pMapping.Mapping.Keys.Contains(prop.Name))
{
if (prop.GetType() == typeof(DateTime))
{
if (pMapping.Mapping[prop.Name] >= 0 && pMapping.Mapping[prop.Name] < values.Length)
{
DateTime tmp;
DateTime.TryParse(values[pMapping.Mapping[prop.Name]], out tmp);
prop.SetValue(this, tmp, null);
}
}
else if (prop.GetType() == typeof(short))
{
if (pMapping.Mapping[prop.Name] >= 0 && pMapping.Mapping[prop.Name] < values.Length)
{
double tmp;
double.TryParse(values[pMapping.Mapping[prop.Name]], out tmp);
prop.SetValue(this, Convert.ToInt16(tmp), null);
}
}
else if (prop.GetType() == typeof(double))
{
if (pMapping.Mapping[prop.Name] >= 0 && pMapping.Mapping[prop.Name] < values.Length)
{
double tmp;
double.TryParse(values[pMapping.Mapping[prop.Name]], out tmp);
prop.SetValue(this, tmp, null);
}
}
else if (prop.GetType() == typeof(string))
{
if (pMapping.Mapping[prop.Name] >= 0 && pMapping.Mapping[prop.Name] < values.Length)
{
prop.SetValue(this, values[pMapping.Mapping[prop.Name]], null);
}
}
}
}
return true;
}
}
Now for my question:
I potentially have several classes that will require this functionality. Would it be beneficial to implement a generic class or an extension class to do the parsing for me? Is my method a sound way to parse CSV data and popluate my object - or is there a better way to do this?
I have read other questions on dynamically parsing CSV, but all deal with the order being known before runtime, whereas i require the user to define the order.

OleDB is great at parsing CSV data and you don't have to use reflection for it. Here's the main idea for mapping with OleDB classes:
User defines a mapping (using delegate, fluent interface or something) and it gets into the Dictionary in your Mapper class.
Parser creates a DataTable and inserts columns from mapper
Parser creates OleDbConnection, Adapter, Command and fills dataTable from CSV file in correct types.
Parser extracts IDataRecords from DataTable and your Mapper needs to map from IDataRecord to objects. For guidance on record-to-object mapping I'd recommend reading sources of ORM mappers like Dapper.NET, Massive, PetaPoco.
OleDb CSV parsing: Load csv into oleDB and force all inferred datatypes to string
UPDATE
Since there's only one string, it goes without saying that using easiest and simplest approach is better. So, for the questions:
Implement generic class - if there's no need to further advance parsing (no more string, no more constraints/features in the future), I'd go for a static class that takes object, string and mapping information. It'd have almost the same look as yours does right now. Here's somewhat modified version (may not compile, but should reflect the general idea):
public static class CSVParser
{
public static void FillPOCO(object poco, string csvData, CSVMapping mapping)
{
PropertyInfo[] relevantProperties = poco.GetType().GetProperties().Where(x => mapping.Mapping.Keys.Contains(x)).ToArray();
string[] dataStrings = csvData.Split(',');
foreach (PropertyInfo property in relevantProperties)
SetPropertyValue(poco, property, dataStrings[mapping.Mapping[property.Name]]);
}
private static void SetPropertyValue(object poco, PropertyInfo property, string value)
{
// .. here goes code to change type to the necessary one ..
property.SetValue(poco, value);
}
}
Regarding the string to typed value conversion - there's Convert.ChangeType method that handles most of the cases. There's particular problem with boolean variables (when it's given "0" instead of "false") though.
As for data population - though reflection is said to be slow, for single objects and seldom usages it should suffice since it's easy and simple. Usual methods for dealing with problem of poco population are: run-time conversion method creation (that uses reflection to be initialized and then is compiled and called like any other method) - usually implemented using DynamicMethod, Expression Trees and similar - there's plenty of topic here on so; usage of dynamic objects (available since C# 4.0) - where to assign/get variable you don't need to declare it; use available libraries on the market (usually from the ORM systems, since they rely heavily on data-to-object conversion).
Personally, I'd measure if reflection is suitable for my performance needs and would progress forward pass the problem.

I would 100% agree with #Dimitriy on this one, as I've wrote 5-10 CSV parsers over the past few weeks.
Edit: (Note this requires saving the text to a temporary file using something like Path.GetTempFile(), but it will allow the flexibility you desire)
The argument of using a DataTable would be best as when the connection string is used properly - using Extended Properties='true;FMT=Delimited;HDR=Yes', it will go into a DataTable and the column headings (which would help you in this case) would be preserved.
So you could write a CSV like
Name,Age,City
Dominic,29,London
Bill,20,Seattle
This generates a DataTable with the column headings you have specified. Otherwise, stick to using the ordinals as you had before.
To integrate this, add a constructor (or extension method which I will get to shortly) that when passed a DataRow will strip out the data:
public UserData(DataRow row)
{
// At this point, the row may be reliable enough for you to
// attempt to reference by column names. If not, fall back to indexes
this.Name = Convert.ToString(row.Table.Columns.Contains("Name") ? row["Name"] : row[0]);
this.Age = Convert.ToInt32(row.Table.Columns.Contains("Age") ? row["Age"] : row[1]);
this.City = Convert.ToString(row.Table.Columns.Contains("City") ? row["City"] : row[2] );
}
Some would argue that the conversion process is not really the responsibility of the UserData class - since it is a POCO. Instead implement either an extension method in a ConverterExtensions.cs class.
public static class ConverterExtensions
{
public static void LoadFromDataRow<UserData>(UserData data, DataRow row)
{
data.Name = Convert.ToString(row.Table.Columns.Contains("Name") ? row["Name"] : row[0]);
data.Age = Convert.ToInt32(row.Table.Columns.Contains("Age") ? row["Age"] : row[1]);
data.City = Convert.ToString(row.Table.Columns.Contains("City") ? row["City"] : row[2] );
}
}
A more architectually sound method is to implement an interface that defines the conversion. Implement that interface with the conversion process and then store that interface reference internally. This will do the conversion for you, keeping the mapping completely seperate and keep your POCO nice and tidy. It will also allow you to "plug-in" mappers.
public interface ILoadFromDataRow<T>
{
void LoadFromDataRow<T>(T object, DataRow dr);
}
public class UserLoadFromDataRow : ILoadFromDataRow<UserData>
{
public void LoadFromDataRow<UserData>(UserData data, DataRow dr)
{
data.Name = Convert.ToString(row.Table.Columns.Contains("Name") ? row["Name"] : row[0]);
data.Age = Convert.ToInt32(row.Table.Columns.Contains("Age") ? row["Age"] : row[1]);
data.City = Convert.ToString(row.Table.Columns.Contains("City") ? row["City"] : row[2] );
}
}
public class UserData
{
private ILoadFromDataRow<UserData> converter;
public UserData(DataRow dr = null, ILoadFromDataRow<UserData> converter = new LoadFromDataRow<UserData>())
{
this.converter = (converter == null ? new LoadFromDataRow<UserData>() : converter);
if(dr!=null)
this.converter.LoadFromDataRow(this,dr);
}
// POCO as before
}
For your scenario, go for the extension methods. This interface method (called segregation) was the way to implement it before extension methods came about.

Related

How to prevent overflow while reading oracle FLOAT(126) with many digits after the decimal to ADO.NET DataTable?

When a database column contains number like 0.11212121212121356500008888888888874343468766, it can't be fit to DataRow's generated Decimal-type column. This same applies to DataReader. With DataReader I have solved this with wrapper:
public class OracleDataReaderWrapper : DbDataReader
{
DbDataReader _realReader;
public OracleDataReaderWrapper(DbDataReader realReader)
{
_realReader = realReader;
}
//... all other methods
public override object GetValue(int ordinal)
{
if (_realReader is System.Data.OracleClient.OracleDataReader)
{
Type fieldType = _realReader.GetFieldType(ordinal);
if (fieldType == typeof(Decimal))
{
return (decimal)((double)((System.Data.OracleClient.OracleNumber)_realReader.GetProviderSpecificValue(ordinal)));
}
//...
But how can I do something with DataSet, DbDataAdapter? Rewriting all datadapter-Select commands with ROUND or TRUNC is not only wrong, it's out of question because there's already hundreds of places to change it.
NOTE this applies also to ODP.NET. There the type is OracleDecimal instead of OracleNumber. My wrapper is used for both clients.
var oracleValue = (OracleDecimal)reader.GetOracleValue(0);
var netValue = (decimal)(OracleDecimal.SetPrecision(oracleValue, 28));
Of course if you are OK with loosing the precision.

Avoiding repetitive job when dealing with many variables

I'm looking for some advices how to deal with similar example problem:
string A;
string B;
string C;
string D;
...
void Initialize()
{
A = someObject.A.ToString();
B = someObject.B.ToString();
C = someObject.C.ToString("F");
D = someObject.D.ToString();
...
}
My class has a lot of numeric variables and I need to pass their values to these strings easily for large quantity of such variables. Let's say it is RPG stats based game and a lot of stats, factors etc. play here a role. Managing such a many variables by copy pasting is a pain.
Question: how can I simplify work with lots of variables.
I would like to know some solutions for this problem since I don't have any experience with it and I don't know anyone or any source to search for a solutions.
I personally thought about using some kind of structure, dicitonary or database.
EDIT: To be precise I've created a class called Character and it has a lot of properties like xp, life, gold etc. Now I want to do a GUI using class called Label that draw text on the screen, so I'm coding GUI class containing Label objects that on various events will react accordingly. For example I need to assign at the beginning to my labels specified text like:
Label life, gold, xp, etc;
life.text = Character.instance.Life.ToString();
gold.text = Character.instance.Gold.ToString();
xp.text = Character.instance.XP.ToString();
...
You should include more details in this question, what you exactly want to achieve.
From the information you provided, I assume you want to read the properties of someObject dynamically, execute ToString() on them and assign its value to some variables. That is a typical reflection assignment. You might want to read a chapter covering reflection on MSDN
If the assumption above is correct, you could do the following:
Dictionary<string, string> propertyValues = new Dictionary<string, string>();
// We access the type information via reflection. What properties your someObject has?
PropertyInfo[] propertyInfos = someObject.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
foreach (var propertyInfo in propertyInfos)
{
// we get the value of the property, described by propertyInfo, from our someObject
object value = propertyInfo.GetValue(someObject, null);
if (value != null)
{
// do your special type handling here and execute ToString()
if(value.GetType() == typeof(int))
propertyValues[propertyInfo.Name] = ((int)value).ToString("F");
if(value.GetType() == ...)
else
propertyValues[propertyInfo.Name] = value.ToString();
}
}
// so if your someObject had a property A you can access it as follows:
string A = propertyValues["A"];
// or you loop the dictionary and do some suff with it (which makes much more sense):
foreach(var keyValuePair in propertyValues)
Console.WriteLine("Property {0} = {1}", keyValuePair.Key, keyValuePair.Value);
It's a little hard for us to say without seeing your exact design/requirements, but a simple way to do this which handles many situations is to store the object itself, rather than copying its properties or fields.
For example, in your version you might have:
private int A;
private string B;
private double C;
public void Initialize(DataObject data)
{
A = data.A;
B = data.B;
C = data.C;
}
public void DoSomething() //Just an arbitrary method using the data
{
return B + " " + A.ToString();
}
Whereas, you could more simply do:
private DataObject _data;
public void Initialize(DataObject data)
{
_data = data;
}
public void DoSomething() //Just an arbitrary method using the data
{
return _data.B + " " + _data.A.ToString();
}
Depending on how the values get into 'someObject', a first step into having less code would be to define the properties to be String, doing the conversion from int to String in the get accessor method. Even though this just moves the ToString() to a different location, it will reduce the code each time you go to get the value.

Iterate through properties and values of an object returned via a linq query on a domain model

I have a custom entity in a relational database that I have mapped to the CLR via a domain model. So by using the following statement, I can pull in an entity from my database into memory via a LINQ query on the domain model, like so;
var inspection = (from i in dbContext.New_testinspectionExtensionBases
where i.New_testinspectionId == currentInspection
select i).First();
There are properties/fields on this entity that I need access to, I need to be able to determine the property/field name as well as it's value. I want to loop through these items in memory, and write out their names and values to the console.
I tried using this approach, but couldn't figure out how to correct the syntax (Nor am I sure that GetProperties is the correct method to use, GetFields wasn't returning anything for some reason so I assumed this was the way to go) but it doesn't really matter since all i need is read access to the value;
var inspectionReportFields = inspection.GetType().GetProperties();
// I called this inspectionReportfields because the entity properties correspond to
// form/report fields I'm generating from this data.
foreach (var reportField in inspectionReportFields)
{
var value = reportField.GetValue();
Console.WriteLine(reportField.Name);
Console.WriteLine(value);
}
Is there an easier way to get the property/field value when utilizing a domain model like EF or openaccess? If not, am I going about it the right way? And lastly, if so, how do I fix the syntax in the value variable declaration?
Here are some sample fields/properties from the code generated by the domain model, for reference;
private int? _new_systemGauges;
public virtual int? New_systemGauges
{
get
{
return this._new_systemGauges;
}
set
{
this._new_systemGauges = value;
}
}
private int? _new_systemAlarm ;
public virtual int? New_systemAlarm
{
get
{
return this._new_systemAlarm;
}
set
{
this._new_systemAlarm = value;
}
}
I assume that you're trying to define a general-purpose way to "dump" an object without knowing anything about its structure. If so, then you are going about things the correct way. You use reflection (GetType() and the associated Type class methods) to inspect the object and return its information.
The reason GetFields() didn't return anything is that you likely did not supply the right binding flags. In particular, if you call the overload that doesn't take any parameters, you only get back public fields; if you want private fields you need to ask for them specifically.
In your case, GetFields(BindingFlags.NonPublic) would give you back the _new_systemGauges and _new_systemAlarm fields, while GetProperties() would give you back the New_systemAlarm and New_systemAlarm properties.
The other key element you missed is that the data you are getting back is the type metadata; it defines the structure of the class, and not any particular instance. If you want to know what the value of a property for a specific instance is, you need to ask for that:
foreach (var prop in obj.GetType().GetProperties())
{
Console.WriteLine("{0} = {1}", prop.Name, prop.GetValue(obj, null));
}
One you have one of the PropertyInfo elements from the type's metadata, you can ask for that property value on any instance of that type. It doesn't have to be the same instance that you originally used. For example:
var objs = somelist.Where(x => x.Id == 1);
foreach (var prop in objs.First().GetType().GetProperties())
{
int x = 0;
foreach (var obj in objs)
{
if (prop.PropertyType.Name.Equals("Int32"))
{
int val = (int)prop.GetValue(obj, null);
Console.WriteLine("Obj #{0}: {1} = 0x{2:x8}", x++, prop.Name, val);
}
else if (prop.PropertyType.Name.Equals("Decimal"))
{
int val = (decimal)prop.GetValue(obj, null);
Console.WriteLine("Obj #{0}: {1} = {2:c2}", x++, prop.Name, val);
}
else
{
Console.WriteLine("Obj #{0}: {1} = '{2}'", x++, prop.Name, prop.GetValue(obj, null));
}
}
}
Technically you should check the result of GetIndexParameters to see if a property is indexed or not; the null parameter to GetValue is actually an array of index values.
To convert the value you get back you can either use typecasts, or if you want to be a bit more flexible, use the Convert class's methods. The difference is, for example, if you have a short property, GetValue() will return a boxed short, which you cannot then typecast as an int; you have to unbox it to a short first. Using Convert.ToInt32() will perform all of the needed steps to get an int value out of any property that is convertible to an integer.
Converting between reference types is easier since you can just use is and as for that; those work just like you'd expect with "reflected" property values.
GetProperties indeed is the correct method.
To get rid of the compiler error, change your code to this:
var value = reportField.GetValue(inspection, null);
You need to pass the instance from which you want to obtain the value, as a PropertyInfo object is not bound to any specific class instance.
Please consider following the standard .NET naming rules.
This would lead to the following:
NewSystemAlarm instead of New_systemAlarm
newSystemAlarm or _newSystemAlarm instead of _new_systemAlarm
NewTestInspectionExtensionBases instead of New_testinspectionExtensionBases
NewTestInspectionId instead of New_testinspectionId
If you are using OpenAccess you always have the complete information about your model classes at your disposal. The information there is retrieved from your mapping which means that you needn't reflect over your classes (no overhead).
Just browse trough context.Metadata.PersistentTypes for all of your classes mapping information.

Comparing two objects' properties simply in c#

I have a class with lots of properties. A shallow copy is enough to fully replicate the object.
I need to compare an object just to check if it contains exactly the same values as another.
My ideas:
The first and most obvious solution is just to create a huge method block that compares each property, one after the other.
The second would be to serialize each object and hash the file or do some sort of md5 checksum on it. (Would this actually work?)
The third is to do some sort of reflection on the object, which would automate the first option, but create an added level of complexity.
Speed isn't really an issue.
I'm interested to hear thoughts, or any other methods I am missing to do such a thing.
Edit:
Thanks all. My solution (Modified to now be recursive on generic items):
public static bool IsSame<T>(T objA, T objB)
{
var type = typeof(T);
var properties = type.GetProperties();
foreach (var pi in properties.Where(a => a.CanRead))
{
if (pi.Name == "Item")
{
var piCount = properties.FirstOrDefault(a => a.Name == "Count");
int count = -1;
if (piCount != null && piCount.PropertyType == typeof(System.Int32))
count = (int)piCount.GetValue(objA, null);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
dynamic child1 = pi.GetValue(objA, new object[] { i });
dynamic child2 = pi.GetValue(objB, new object[] { i });
return IsSame(child1, child2);
}
}
}
else
{
var val1 = type.GetProperty(pi.Name).GetValue(objA, null);
var val2 = type.GetProperty(pi.Name).GetValue(objB, null);
if (val1 != val2 && (val1 == null || !val1.Equals(val2)))
return false;
}
}
return true;
}
Most serializers are designed to ensure that data retains its integrity during serialization and deserialization, not to produce a consistent serialized format. I would avoid using serialization for this purpose.
You may consider implementing IEquatable, to have each instance capable of comparing itself with instances of the same type. Or a class do do the comparisons for you that implements IEqualityComparer. How they do this comparison may be the 'big method' that compares properties one after the other, or uses reflection.
Reflection can be a fairly quick and simple way to achieve your goal but can cause problems down the line (for example if someone adds a property to your type that should not be included for comparing equality), but obviously the converse is also true (someone adds a property that should be checked for equality, but the equality comparison isn't updated). Which approach you use should generally be decided by how comfortable the team is with each approach in tandem with the context in which the class will be used.
In your case I'd probably recommend using the reflection based approach since you wish to check the result of a shallow clone operation, so all properties should be equal.
As an aside, I'd recommend using the MemberwiseClone method to create the clone, which would lessen the need for such stringent tests.
The third option (reflection) would be the slowest, but it would also be the most robust/testable.
The hash code would be very similar to the first option, since you would have to call all of your member variables, so 1 and 2 would require you to update your .Equals(obj) and .GenerateHash() methods every time you modify your member variable lists.
Here is some code to get you started:
foreach (FieldInfo field in this.GetType().GetFields())
{
if (o[field.Name] == null)
{
if (!field.GetValue(this).Equals(o[field.Name]))
return false;
}
else
{
return false;
}
}
return true;
Another thought is that if the properties return simple value types you could group them into immutable value types of their own. For instance, if you have a customer with properties string Address1 string Address2 string City string State string Zip, you could create a value type Address that implements its own equality comparer and use that.
Not sure if this applies to your situation, but I've found that when I have a class with a lot of properties, it is often possible to do this, and it tends to make my classes simpler and easier to reason about.
If you serialize you have to specify the serialization order on each Field/Property to ensure that all data is serialized int the same order. But all you would achieve is to implement GetHashCode() in an external class.
GetHashCode() has some examples on how to override it, so look there first.
If your class has a lot of fields, and you don't want to write all the code by hand. You could use reflection to autogenerate the code. If your class changes from time to time then you could create a partial class with the GetHashCode() implementation in a T4 template.

Generic method to recive any type of object and convert the object to a List<string>

EDIT AGAIN: the solution was probably different from my original question. Thanks everyone very much your great ideas. I wish I could vote for more than one answer.
EDIT: I am populating a Jquery table plugin from datatables/.net and it requires the data (Json) to be in a certain format like this;
"sEcho": 1,
"iTotalRecords": 57,
"iTotalDisplayRecords": 57,
"aaData": [
[
"Gecko",
"Firefox 1.0",
"Win 98+ / OSX.2+",
"1.7",
"A"
],
[
"Gecko",
"Firefox 1.5",
"Win 98+ / OSX.2+",
"1.8",
"A"
],
...
]
}
I am recieving data from a service that is returning a collection of object. I would like one method which I can pass these collections into and it will return the appropriate string
thanks
END EDIT
I would like to build a method that can receive and object that we build and will return an array List each containing the value of each object passed in. For example;
I have a collection of 'Car' objects
What I would like to do is
public object[] Something<T>(_cars)
{
object[] objArray = new object[_cars.Count];
foreach(Car _car in _cars ){
IList objList = new List<string>;
objList.Add(_car.Color);
objList.Add(_car.EngineSize);
//etc etc
objArray[i] = objList;//i'll have to use a for loop to get the i counter but you get my idea
}
return objArray
}
my problem is how can I access the properties of the object without knowing what type of object it is?
thanks for any help
Update: To answer your revised question - produce a JSON result of a data structure - use the built-in JavaScriptSerializer class:
JavaScriptSerializer serializer = new JavaScriptSerializer();
string json = seriaizer.Serialize(myObjectOrArray);
Below is the previous answer.
how can I access the properties of the object without knowing what type of object it is
Using Reflection, and grabbing the properties which are strings. Note this is not necessarily a good idea. The fact that you have to use reflection to get what you want is usually a HUGE WARNING FLAG that your design is wrong.
However, in the hopes of learning something useful, here's how it could be done:
public object[] Something<T>(T[] items)
{
IList objList = new List<object>();
//get the properties on which are strings
PropertyInfo[] properties = typeof(T).GetProperties().Where(p => p.PropertyType == typeof(string));
foreach(T item in items)
{
IList stringList = new List<string>;
foreach(PropertyInfo property in properties)
{
objList.Add(property.GetValue(item, null) as string);
}
objList.Add(stringList);
}
}
return objList.ToArray();
}
A far, far better solution would be to require all the objects coming into this method to conform to some interface that requires them to provide their own string-formatted data. Or maybe take two steps back and ask for help on the underlying problem. This approach is fraught with problems. It's a rabbit hole you don't want to go down.
Use the System.Web.Script.Serialization.JavaScriptSerializer class. It was specifically provided for JSON serialization.
using System.Web.Script.Serialization;
public string ToJson(object o)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Serialize(o);
}
EDIT: Oops, I missed that your plugin doesn't want a true JSON representation of the objects; it just wants arrays of values. You could use reflection to iterate over the properties of the objects as others have suggested, but then you have no control over which properties end up in which columns. It is not clear from your question whether that is a problem for you.
If you need a strict mapping between properties and columns, then you will have to define that somehow in C#. To do this you could implement IEnumerable as Ed demonstrates or create a custom interface:
public interface ITableDataSource
{
IList<string> GetTableData();
}
Then implement this on any objects that might need to be data sources for the jQuery table plugin:
public class Car : ITableDataSource
{
//...class implementation details...
public IList<string> GetTableData()
{
return new List<string>()
{
this.Color,
this.EngineSize,
this.NumberOfSeats.ToString()
};
}
}
Finally, in your method that is returning the data to the jQuery plugin, use the interface to construct your response object, then pass it to my ToJson() method to serialize it:
public string DoSomething(IList<ITableDataSource> objects)
{
var result = new
{
sEcho = 1,
iTotalRecords = 1,
iTotalDisplayRecords = 1,
aaData = new List<IList<string>>()
};
foreach (ITableDataSource ds in objects)
result.aaData.Add(ds.GetTableData());
return ToJson(result);
}
While it would be relatively straightforward to use reflection to loop through all of your objects and all the properties on those objects to build that string, it's already been written.
I would highly recommend looking at the Json.NET project found here. Add this DLL to your project and converting a list of objects into a Json formatted string is as easy as:
string json = Newtonsoft.Json.JsonConvert.SerializeObject( listOfCars );
IList objList = new List<string>();
foreach ( PropertyInfo prop in _car.GetType().GetProperties() )
{
var value = prop.GetValue( _car, null );
objList.Add( value != null ? value.ToString() : null );
}
objArray[i] = objList;
The code to get the Property values of an object is
foreach (PropertyInfo info in myObject.GetType().GetProperties())
{
if (info.CanRead)
{
object o = propertyInfo.GetValue(myObject, null);
}
}
my problem is how can I access the properties of the object without knowing what type of object it is?
Well, in the general sense you can't. Generics is all about treating objects generically. However, you can impose type constraints by using a where clause. Based on the foreach loop I would say constrain your types to types that implement IEnumerable, but then you go on to use properties like "Color" and "EngineSize", which are very specific. I don't even know why you would have properties named "Color" and "EngineSize" that are strings, but that is another problem altogether...
It seems like the best approach for you would be to define an interface or an abstract base class that each of these objects inherits from. Then you can use the 'where' clause to constrain to objects of that interface/base class only So...
public object[] Something<T>( T _cars) where T : IEnumerable<MyInterface>
However, if we are going to go down this road I don't see why the method should be generic at all. It could simply take an IEnumerable<T> as an input. When we only want to use one type in a method generics is not needed.

Categories