【问题标题】:Generic Method. Assigining Properties from a DataReader to Generic Objects通用方法。将属性从 DataReader 分配给通用对象
【发布时间】:2010-11-05 18:25:06
【问题描述】:

早上好,我从一堆 Google 搜索中创建了我的第一个通用方法。我希望有人检查一下,如果我违反了任何主要规则,或者是否有办法改进这种方法,请告诉我。

该方法调用 sql 中的存储过程,然后根据从 DataReader 架构中读取的值使用反射来分配属性。对存储过程进行了编码,以便它们返回类所期望的确切属性名称。代码如下:

       public static List<T> GetList<T>(string SQLServer, string DBName,
        string ProcedureName, Dictionary<string, string> Parameters )
         where T : new()
    {
        List<T> list = new List<T>();

        //Setup connection to SQL
        SqlConnection SqlConn = new SqlConnection(ConnectionString(SQLServer, DBName));
        SqlCommand SqlCmd = new SqlCommand(ProcedureName, SqlConn);
        SqlCmd.CommandType = System.Data.CommandType.StoredProcedure;
        SqlDataReader reader;

        //Process Parameters if there are any
        foreach (KeyValuePair<string, string> param in Parameters)
        {
            SqlCmd.Parameters.AddWithValue(param.Key, param.Value);
        }

        SqlConn.Open();
        reader = SqlCmd.ExecuteReader();

        //Get The Schema from the Reader
        //The stored procedure has code to return
        //the exact names expected by the properties of T
        DataTable schemaTable = reader.GetSchemaTable();
        List<string> fields = new List<string>();
        foreach (DataRow r in schemaTable.Rows)
        {
            fields.Add(r[0].ToString());
        }


        while (reader.Read())
        {
            T record = new T();

            foreach (string field in fields)
            {
                //Assign the properties using reflection
                record.GetType().GetProperty(field).SetValue(
                    record, reader[field],
                    System.Reflection.BindingFlags.Default,
                    null,null,null);
            }

            list.Add(record);
        }
        return list;
    }

【问题讨论】:

标签: c# generics methods class-design


【解决方案1】:

我不知道我是否会这样做。我可能会先使用 ORM,例如实体框架。不过,我过去也做过类似的事情,但也有一些缺点:

  • 反射可能比只指定所有内容要慢,具体取决于多少,这对您来说可能根本不是问题。
  • 对我来说,更大的问题只是你冒着更多运行时错误而不是编译时错误的风险,这样可以节省前期时间,但从长远来看可能会引入烦人的错误。

关于我唯一肯定要说的就是确保使用 try/catch/finally、try/finally,或者将 SqlConnection、SqlCommand 和 SqlDataReader 包装在 using() 中。我只花了2天时间重构,因为以前的开发者没有关闭任何连接或数据读取器,并且连接池正在炸毁并拒绝连接。

【讨论】:

  • 这是快速寻找解决方案的东西。稍后我将添加错误检查等。我什至不确定我会使用这个。从我目前得到的回复来看,使用反射似乎是个坏主意。
【解决方案2】:

虽然这种方法确实有效,但您肯定希望添加一些错误处理。

还有一些现有的库可以为您执行此操作,例如 AutoMapper。您还可以查看其他 ORM,例如 SubSonic、Linq2SQL、EntityFramework、NHibernate 等...

还要注意反射非常慢,尤其是像这样一遍又一遍地进行。如果这将在大型企业重负载系统中,您最好在第一次遇到映射时生成 ta 动态方法和 IT 代码来进行映射,然后一遍又一遍地重新运行相同的动态方法,而不是依赖反射。

【讨论】:

  • 感谢您的意见。您能否提供更多关于在这种情况下生成动态方法的信息?
  • 我不记得我是从哪里知道如何做到这一点的,但是您可以在 Google 上搜索“.net 动态方法”之类的内容或查看 System.Reflection.Emit 命名空间的 MSDN 文档,主要是 DynamicMethod 和 ILGenerator 类。即时发出 IL 可能相当烦人且难以调试,但最终会获得很大的速度回报。
猜你喜欢
  • 1970-01-01
  • 2014-04-05
  • 1970-01-01
  • 2018-11-18
  • 1970-01-01
  • 2013-05-11
  • 1970-01-01
  • 2016-03-31
  • 2011-09-22
相关资源
最近更新 更多