2009-05-27 117 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);