简化代码的通用函数

时间:2009-05-27 07:16:41

标签: c# generics

我有以下方法:

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

2 个答案:

答案 0 :(得分:1)

这一切看起来有点模糊和复杂,但要直接回答你的问题 - 为了使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 :(得分: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);