[英]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.