[英]trying to create generic Type Reader using reflection
此问题的扩展, 将静态反射信息传递给静态泛型方法
我试图创建一个通用类型读取器,因为我使用类做了很多数据访问,而且我试图创建一个相当通用的方法,该方法无需太多代码即可读取数据。
大部分阅读内容的代码部分看起来像这样
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));
}
但是,这将引发无效的强制转换异常。
readXXX方法工作正常,每个return语句中都出现问题
我也尝试过使用
public static T SafeConvert<T>(string s, T defaultValue)
{
if ( string.IsNullOrEmpty(s) )
return defaultValue;
return (T)Convert.ChangeType(s, typeof(T));
}
但仍然失败
编辑:
该方法通过
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 );
更多...
人们似乎在问我用它做什么,最终它允许我在一行中创建一个可以通过传递文件Location或sql query从CSV或SQL的任何源读取的枚举数。
//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",",");
我现在正在运行它,但是在每个实现中都需要重复一长串if dataType == typeof(string)的操作,我希望将其重构为单个通用的Read方法,但是在Convert时遇到了麻烦
您更新的问题说可以,但是您想重构。 好吧,你可以!
Dictionary<Type, Func<string, IDataRecord, object>> converters_ = new Dictionary<Type, Func<string, IDataRecord, object>>();
converters_[typeof(bool)] = (s) => { return readBoolN( data[s].ToString() ); };
// repeat for other types:
Then
public static T Read<T>(string field,IDataRecord data )
{
return (T)converters_[typeof(T)](field, data);
}
您在没有Binder
情况下调用GetMethod
,如何获得所需的泛型之一?
Read<T>
将在不带参数的情况下被调用以推断类型,您是否希望每次使用类型参数调用它时都可以?
如果您期望的是2,那么与仅调用GetXXX
方法有何不同?
我无法遵循您的原始设计,但是请考虑以下代码:
public static partial class DataReaderExtensions {
/// <summary>
/// <para>Copy data to target object</para>
/// <para>Class which implements IDataRecord usually also implements IDataReader</para>
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data"></param>
/// <param name="target"></param>
/// <returns>the count of field or property copied</returns>
public static int CopyTo<T>(this IDataRecord data, T target) {
return (
from column in
Enumerable.Range(0, data.FieldCount).Select(
(x, i) => new {
DataType=data.GetFieldType(i),
ColumnName=data.GetName(i)
}
)
let type=target.GetType()
from member in type.GetMembers()
let typeMember=
member is PropertyInfo
?(member as PropertyInfo).PropertyType
:member is FieldInfo
?(member as FieldInfo).FieldType
:default(MemberInfo)
where typeMember==column.DataType
let name=member.Name
where name==column.ColumnName
let invokeAttr=
BindingFlags.SetProperty|BindingFlags.SetField|
BindingFlags.NonPublic|BindingFlags.Public|
BindingFlags.Instance
select type.InvokeMember(name, invokeAttr, default(Binder), target, new[] { data[name] })
).Count();
}
}
您可以通过如下语句将data
直接复制到自定义类型的实例:
reader.CopyTo(myObject);
无论公共/非公共,它都会自动将列名称与字段/属性映射。 最后返回复制元素的数量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.