I had a situation where I had a SQL statement stored against a row in a database. Depending on the row would depend on what data was output. For example, row 1 would return all the industries and row 2 would return all the age groups and so on. Each of my tables has it's own C# class/object associated to it. So I have an
Industry class and an
AgeGroup class and so on.
The data that has the SQL logged against it was a table and object called
PersonalDetail and the SQL was stored in a column/property called LookUpStatement. I wanted to get an Ilist<> of the data results that LookUpStatement returns when executed. The key thing I wanted to achieve was that the new method would return the IList<> strongly typed. So in the case of the industry data I would have IList<Industry> returned by it or for AgeGroup an IList<AgeGroup>.
The whole passing and returning of dynamic types has been something I have wanted to master for some time. After some extensive searching and no single article telling me exactly what I needed I managed to pile it all together and ended with this...
Calling and using it:
//Get the personal detail row that is required
// The Load method loads a specifc row from the database
// In this instance, row 1 LookUpStatement will select all industires (e.g. SELECT * FROM [Industry])
PersonalDetail personalDetail = PersonalDetail.Load(1);
//Get the industries as an IList from the personal detail object
IList<Industry> industries = personalDetail.LookUpData<List<Indstry>>();
Note that the
LookUpData call is made using a
List<> and not an
IList<>.The code itself:
public class PersonalDetail
{
public LookUpStatement
{
get; set;
}
//Other properties, constructor, etc...
public T LookUpData<T>()
{
if (!typeof(T).Name.StartsWith("List"))
throw new ArgumentException("The generic pass type must be a List<>");
//Create a typed instance of the required List
T os = (T)Activator.CreateInstance(typeof(T));
//Get the base object propertype. e.g. Industry
Type propType = typeof(T).GetProperty("Item").PropertyType;
//Get the data as a DataSet
DataSet ds = _DB.GetDataSet(this.LookUpStatement);
//Iterate the data
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
//Get the data row
DataRow dr = ds.Tables[0].Rows[i];
//Use relfection to execute the Add method of the dynmaic List
//Then use relfection to execute the LogItem method of the base object
// Logitem converts the data row into the base object. e.g. Industry
os.GetType().GetMethod("Add").Invoke(
os,
new object[] {
propType.GetMethod("LogItem").Invoke(null, new object[] { dr })
}
);
}
}
}
The comments in the code should hopefully give an indication of how it works. Working out the
T os = (T)Activator.CreateInstance(typeof(T)); took a while as defining the
os object as
IList<object> just wasn't working. Got there in the end though :)