2009-05-27 2 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 общий метод, но как?

Я не вижу, как заменить

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

с 1 общей линии, а также

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' в методах «Populate»; является «типом» клиента/адреса и т. д.? Почему сложный CreateInstanceAndUnwrap? Также - будьте осторожны с SQL-инъекцией ... –

+0

Также: propertyitem; вы передаете это как 'o' и (отдельно) call propertyitem.ToString() - я не думаю, что это хорошая идея ... что он пытается сделать? –

+0

прояснить несколько вещей; Раннее утро, кофе еще не пинжал - но пропласт не нужен, скопирован и вставлен из предыдущей попытки этой проблемы. Таким образом, CreateInstanceAndUnwrap также избыточен. Клиент, адрес, метр и расписание - это типы. Иерархия: JobCard содержит TimeSheet, Neter, Customer (который содержит адрес). SQL-инъекция не является проблемой, так как эти методы вызывают через проверенное приложение WM5 через webservice. – callisto

ответ

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; 
} 
+0

Обратите внимание, что «экземпляр», «proplist» и «obj» (из нового T()) все отбрасываются без фактического использования (ошибка в исходном коде) –

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); 

В качестве альтернативы; передать идентификатор в качестве аргумента:

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); 
+0

DBObjectRetrieveAttribute ora = ReflectionHelper.GetAttribute (typeof (T)); не работает. :( T не является таким же, как propertyitem.PropertyType T Name = "Customer", но propertyitem.PropertyType Name = "CustomerBase'1" – callisto

+0

Ну ладно, но что-то вдоль этих строк.Поскольку CustomerBase1 не упоминался, я не мог этого предсказать! –