I was doing some work on a function that takes in a list of generic items, and converts them into a Sqlparameter that has been packed to interface with a SQL datatable parameter type. The challenge is that, the way the data will need to be packed will vary slightly if it is a simple list of what I will call atomic types, such as ints, floats, bools, and strings, versus how it will be processed if it is a collection of classes with public properties.
My function looks something like this:
public static SqlParameter ConvertObjectCollectionToParameter<T>
(string parameterName, string sqlTypeName, IEnumerable<T> input)
{
var dt = new DataTable();
var genericType = typeof(T);
// This bit is a hack
var atomicTypes = new HashSet<string>()
{
"System.Int32","System.String","System.Double","System.Float","System.Boolean","System.DateTime",
"System.DateTimeOffset","System.TimeSpan","System.Guid","System.Single","System.Decimal",
"System.Byte","System.Byte[]","System.SByte","System.Char","System.UInt32","System.Int64",
"System.UInt64", "System.Object", "System.Int16"
};
// this is the line that would be nice to replace with refelection
if (atomicTypes.Contains(genericType.FullName))
{
// todo - convert list elements into datatable rows
}
else
{
// this block works just fine right now with classes,
// but note that there are any number of non-classes
// not in the hashset that could be passed in here that
// will cause this code to fail.
var objectProperties = genericType.GetProperties();
foreach (var propertyInfo in objectProperties)
dt.Columns.Add(propertyInfo.Name);
foreach (var item in input)
{
var dr = dt.NewRow();
foreach (var property in objectProperties)
dr[property.Name] = genericType.GetProperty(property.Name).GetValue(item, null);
dt.Rows.Add(dr);
}
}
var sql_parameter = new SqlParameter()
{
ParameterName = parameterName,
SqlDbType = SqlDbType.Structured,
TypeName = sqlTypeName,
Value = dt,
};
return sql_parameter;
}
I have tried to look at the properties of the generic type by looking at typeof(T), but unfortunately, I dont see anything that would distinguish these two types. Even the obvious looking IsClass property is true for both arbitrary classes and Strings when passed in, since the reflection is looking at the String object wrapper class that lurks under a C# string.
Any suggestions? I can deal with the specific cases easily enough, but just telling the two categories apart is pretty tricky. If I cannot do this with reflection, I am going to have to just make a list of every atomic type and check that each time. That seems pretty inelegant, though, so I'd like to avoid that approach if possible.