An Extension to this question passing static reflection information to static generic methods
Im trying to create a Generic Type Reader as i do a lot of data access using Classes and i'm trying to create a fairly generic method that allows to read data without much code.
the part of the code that does most of the reading looks like this
public static T Read<T>(string field,IDataRecord data )
{
Type type1 = typeof (T);
try
{
if (type1 == typeof( String ))
{
return (T)Convert.ChangeType( readString( data[field].ToString() ), typeof( T ) );
}
if (type1 == typeof( int? ))
{
return (T)Convert.ChangeType( readIntN( data[field].ToString() ), typeof( T ) );
}
if (type1 == typeof( Guid? ))
{
return (T)Convert.ChangeType( readGuidN( data[field].ToString() ), typeof( T ) );
}
if (type1 == typeof( double? ))
{
return (T)Convert.ChangeType( readDoubleN( data[field].ToString() ), typeof( T ) );
}
if (type1 == typeof( decimal? ))
{
var res = readDecimalN(data[field].ToString());
return (T)Convert.ChangeType( res, typeof( T ) );
}
if (type1 == typeof( float? ))
{
return (T)Convert.ChangeType( readFloatN( data[field].ToString() ), typeof( T ) );
}
if (type1 == typeof( bool? ))
{
return (T)Convert.ChangeType( readBoolN( data[field].ToString() ), typeof( T ) );
}
if (type1 == typeof( DateTime? ))
{
return (T)Convert.ChangeType( readDatetimeN( data[field].ToString() ), typeof( T ) );
}
if (type1 == typeof( int ))
{
return (T)Convert.ChangeType( readInt( data[field].ToString() ), typeof( T ) );
}
if (type1 == typeof( long? ))
{
return (T)Convert.ChangeType( readLongN( data[field].ToString() ), typeof( T ) );
}
if (type1 == typeof( long ))
{
return (T)Convert.ChangeType( readLong( data[field].ToString() ), typeof( T ) );
}
if (type1 == typeof( Guid ))
{
return (T)Convert.ChangeType(readGuid( data[field].ToString() ), typeof( T ) );
}
if (type1 == typeof( double ))
{
return (T)Convert.ChangeType( readDouble( data[field].ToString() ), typeof( T ) );
}
if (type1 == typeof( decimal ))
{
return (T)Convert.ChangeType( readDecimal( data[field].ToString() ), typeof( T ) );
}
if (type1 == typeof( float ) || type1 == typeof( Single ))
{
return (T)Convert.ChangeType( readFloat( data[field].ToString() ), typeof( T ) );
}
if (type1 == typeof( bool ))
{
return (T)Convert.ChangeType( readBool( data[field].ToString() ), typeof( T ) );
}
if (type1 == typeof( DateTime ))
{
return (T)Convert.ChangeType( readDatetime( data[field].ToString() ), typeof( T ) );
}
}
catch (Exception)
{
throw;
}
throw new Exception(String.Format("Data Type Not Supported: {0}", type1));
}
However this is throwing an Invalid Cast Exception.
the readXXX methods are working fine the issue is occuring in each of the return statements
i have also tried using
public static T SafeConvert<T>(string s, T defaultValue)
{
if ( string.IsNullOrEmpty(s) )
return defaultValue;
return (T)Convert.ChangeType(s, typeof(T));
}
but it is still failing
Edit:
the method is being called via
private static List<T> GetItems<T>(IDataReader reader)
{
var items = new List<T>();
while (reader.Read())
{
Type type1 = typeof (T);
var item = (T) Activator.CreateInstance(typeof (T), new object[] {});
foreach (PropertyInfo info in type1.GetProperties())
{
int written = 0;
if (info.CanWrite)
{
#region
try
{
Type dataType = info.PropertyType;
MethodInfo method = typeof (DataReader).GetMethod("Read",BindingFlags.Static | BindingFlags.Public);
MethodInfo generic = method.MakeGenericMethod(dataType);
var t = generic.Invoke(null, new object[] {info.Name, reader});
info.SetValue( item, t );
More...
People seem to be asking what i use this for, and ultimately it allows me to in one line create an ienumerable that is read from any source be it CSV or SQL by passing a file Location or sql query i.e.
//returns Ienumerable<MyClass>
var list = Reader.ReadSql<MyClass>(DataBases.Test,"select * from TestTable where someAttribute = 1");
// also returns Ienumerable MyClass
var list2 = Readre.ReadCsv<MyClass>(@"c:\file1.csv",",");
I have it running now but it requires repetiiton of the long list of if dataType == typeof(string) in each implementation i was hoping to refactor that into the single generic Read method but am having trouble with the Convert