2009-05-27 152 views
0

泛型函數,我有以下方法:簡化代碼

private JobCard PopulateObject(JobCard jc, DataRow dataRow) 
{ 

    PropertyInfo[] proplist = jc.GetType().GetProperties(); 

    foreach (PropertyInfo propertyitem in proplist) 
    { 
     if (propertyitem.Name != "") 
      if (propertyitem.PropertyType.BaseType.Namespace == "System") 
      { 
       propertyitem.SetValue(jc, dataRow[propertyitem.Name], null);     
      } 
      else 
      { 
       string typename = propertyitem.ToString().Replace("Pss.Common.Mia.", ""); 
       int i = typename.IndexOf("Base"); 
       typename = typename.Substring(0, i); 
       Type type = propertyitem.PropertyType; 

       switch (typename) 
       { 
        case "Customer": 
         propertyitem.SetValue(jc, PopulateCustomerObject(propertyitem, dataRow, type), null); 
         break; 
        case "Meter": 
         propertyitem.SetValue(jc, PopulateMeterObject(propertyitem, dataRow, type), null); 
         break; 
        case "TimeSheet": 
         propertyitem.SetValue(jc, PopulateTimeSheetObject(propertyitem, dataRow, type), null); 
         break; 
       } 
      } 
    } 

    return jc; 

} 

以上方法調用這些:

private Customer PopulateCustomerObject(object o, DataRow dataRow, Type type) 
    { 
      IDataStorable instance = (IDataStorable)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName); 
     PropertyInfo[] proplist = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); 

     Customer c = new Customer(); 

    Guid customerGuid = new Guid(dataRow["AddressId"].ToString()); 
    string view = ReflectionHelper.GetAttribute<DBObjectRetrieveAttribute>(type).View; 

    string query = string.Format("select * from {0} where id = '{1}'", view, customerGuid); 

    c = DataAccess.Retriever.Retrieve<Customer>(query); 

    return c; 
} 


private Address PopulateAddressObject(object o, DataRow dataRow, Type type) 
{ 
    IDataStorable instance = (IDataStorable)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName); 
    PropertyInfo[] proplist = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); 

    Address a = new Address(); 

    Guid AddressGuid = new Guid(dataRow["PhysicalAddressId"].ToString()); 
    string view = ReflectionHelper.GetAttribute<DBObjectRetrieveAttribute>(type).View; 

    string query = string.Format("select * from {0} where id = '{1}'", view, AddressGuid); 

    a = DataAccess.Retriever.Retrieve<Address>(query); 
    return a; 
} 

private Meter PopulateMeterObject(object o, DataRow dataRow, Type type) 
{ 

    IDataStorable instance = (IDataStorable)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName); 
    PropertyInfo[] proplist = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); 

    Meter m = new Meter(); 

    Guid meterGuid = new Guid(dataRow["MeterId"].ToString()); 
    string view = ReflectionHelper.GetAttribute<DBObjectRetrieveAttribute>(type).View; 

    string query = string.Format("select * from {0} where id = '{1}'", view, meterGuid); 

    m = DataAccess.Retriever.Retrieve<Meter>(query); 
    return m; 
} 

,我可以看到將最好的1種泛型方法所取代,但如何?

我不明白如何與1條普通線路取代

Customer c = new Customer(); 
Address a = new Address(); 
Meter m = new Meter(); 
TimeSheet t = new TimeSheet(); 

,也

c = DataAccess.Retriever.Retrieve<Customer>(query); 
a = DataAccess.Retriever.Retrieve<Address>(query); 
m = DataAccess.Retriever.Retrieve<Meter>(query); 
t = DataAccess.Retriever.Retrieve<TimeSheet>(query); 

我不能改變Retriever.Retrieve。它被聲明爲

public static T Retrieve<T>(string query) 
      where T : IDataStorable 
     { 
      return Retrieve<T>(query, new IDbDataParameter[0], string.Empty); 
     } 
+0

請澄清一些事情;目前尚不清楚在「填充」方法中如何使用`proplist`或`o`;是'類型'客戶/地址等?爲什麼複雜的CreateInstanceAndUnwrap?另外 - 謹防SQL注入... – 2009-05-27 07:27:45

+0

另請參見:propertyitem;你將它作爲`o`傳遞,然後(分別)調用propertyitem.ToString() - 我不認爲這是一個好主意......它試圖做什麼? – 2009-05-27 07:29:56

+0

澄清了一些事情;早期的mornig,咖啡還沒有被踢過 - 但是這個列表是不必要的,從之前的這個問題的嘗試中複製並粘貼。因此CreateInstanceAndUnwrap也是多餘的。客戶,地址,計量表和時間表是類型。層次結構是:JobCard包含TimeSheet,Neter,Customer(它包含Address)SQL注入不是問題,因爲這些方法是通過經過驗證的WM5應用程序跨web服務調用的 – callisto 2009-05-27 08:03:39

回答

1

這一切似乎有點晦澀,複雜的,但直接回答你的問題 - 以genericise你PopulateAddressObject功能,你可以做這樣的事情:

private TPopulateAddressObject(object o, DataRow dataRow, Type type, string idColumnName) where T : IDataStorable, new() 
{ 
    IDataStorable instance = (IDataStorable)AppDomain.CurrentDomain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName); 
    PropertyInfo[] proplist = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); 

    T obj = new T(); 

    Guid id = new Guid(dataRow[idColumnName].ToString()); 
    string view = ReflectionHelper.GetAttribute<DBObjectRetrieveAttribute>(type).View; 

    string query = string.Format("select * from {0} where id = '{1}'", view, id); 

    obj = DataAccess.Retriever.Retrieve<T>(query); 
    return obj; 
} 
1

還有就是Populate*方法中的很多東西,你只是不使用;例如,你不實際使用你花費大量的時間創建對象...

如何添加PrimaryKey屬性[DBObjectRetrieveAttribute](持有映射DataRow列),以及類似:

private static T Populate<T>(DataRow dataRow) 
    where T : class, IDataStorable, new() 
{ 
    DBObjectRetrieveAttribute ora = 
     ReflectionHelper.GetAttribute<DBObjectRetrieveAttribute>(typeof(T)); 
    string view = ora.View; 
    Guid pkid = new Guid(dataRow[ora.PrimaryKey].ToString()); 
    // beware SQL injection... 
    string query = string.Format("select * from {0} where id = '{1}'", 
     view, pkid); 

    return DataAccess.Retriever.Retrieve<T>(query); 
} 

然後不需要打開不同的屬性類型;您可以使用MakeGenericMethod

object obj = MethodInfo mtd = typeof(SomeType).GetMethod("Populate", 
     BindingFlags.NonPublic | BindingFlags.Static) 
    .MakeGenericMethod(propertyitem.PropertyType) 
    .Invoke(null, new object[] {dataRow}); 
propertyitem.SetValue(jc, obj, null); 

或者,通過ID作爲一個參數:

private static T Populate<T>(DataRow dataRow, string primaryKey) 
    where T : class, IDataStorable, new() 
{ 
    ... snip 
    Guid pkid = new Guid(dataRow[primaryKey].ToString()); 
    ... snip 
} 

而且做這樣的事情:

object obj; 
if(type == typeof(Customer)) { 
    obj = Populate<Customer>(dataRow, "AddressId"); 
} else if (type == typeof(Meter)) { 
    obj = Populate<Meter>(dataRow, "MeterId"); 
} else if (...etc...) { 

} else { 
    throw new InvalidOperationException("Type is not supported: " + type.Name); 
} 
propertyitem.SetValue(jc, obj, null);