如何接受Func<>列表在func<>列表中委托并返回列表列表处理不同的对象

时间:2015-10-28 07:42:41

标签: c# generics list

以下是我的代码,我将一个存储过程作为SQL执行,它运行多个Select语句。现在每个datareader.NextResult()的输出将是一个不同的对象(一个POCO类),它们将不依赖(因此我不能有一个接口/基类来访问它们)。这种方法的问题是我必须在SelectQuery返回的列表上进行类型转换。有没有更好的方法来实现以下,以便我可以避免类型转换?

public IEnumerable<IEnumerable<T>> SelectQuery<T>(string strSql, List<Func<IDataRecord, T>> infoExtractors)
{
  var result = new List<List<T>>();

  using (var connection = GetDBConnection())
  {
    using (var command = GetDBCommand(strSql))
    {
      command.Connection = connection;
      connection.Open();
      using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
      {
        try
        {
          int i = 0;
          List<T> curList = new List<T>();
          result.Add(curList);
          while (reader.Read())
          {
            curList.Add(infoExtractors[i](reader));
          }

          while(reader.NextResult())
          {
            i++;
            curList = new List<T>();
            result.Add(curList);
            while (reader.Read())
            {
              curList.Add(infoExtractors[i](reader));
            }
          }
        }
        finally
        {
          reader.Close();
        }
      }
    }
  }

  return result;
}

此代码的主要目的是避免让调用者关闭数据库连接

以下是我编写的示例代码,用于模拟此操作并检查是否可以避免类型转换

class Program
  {
    static void Main(string[] args)
    {

      List<Func<int, object>> lst = new List<Func<int, object>>();      
      lst.Add(c1.SetThis);      
      lst.Add(c2.SetThis);
      lst.Add(c3.SetThis);
      var output=  Check(lst);


      foreach(var cur in output)
      {
        foreach(var innerCur in cur)
        {
          System.Console.Write(innerCur);
        }
        System.Console.WriteLine();
      }
      System.Console.ReadLine();
    }

    static List<List<T>> Check<T>(List<Func<int, T>> inpList) 
    {
      List<List<T>> lst = new List<List<T>>();

      lst.Add(new List<T>() { inpList[0](10) });
      lst.Add(new List<T>() { inpList[1](20) });
      lst.Add(new List<T>() { inpList[2](30) });

      return lst;
    }


  }

  class c1
  {
    internal int num;

    internal static c1 SetThis(int i)
    {
      c1 c1Obj= new c1();
      c1Obj.num = i;
      return c1Obj;
    }
  }

  class c2
  {
    internal int num;
    internal static c2 SetThis(int i)
    {
      c2 c2Obj = new c2();
      c2Obj.num = i;
      return c2Obj;
    }
  }

  class c3
  {
    internal int num;
    internal static c3 SetThis(int i)
    {
      c3 c3Obj = new c3();
      c3Obj.num = i;
      return c3Obj;
    }
  }

现在,虽然测试样本具有相同的方法名称,但实际上类c1,c2,c3将保存不同的数据。另外 innerCur 的内部foreach循环打印类型,但我需要一种方法来获取值而不使用类型转换?可能吗?在最坏的情况下,我将不得不摆脱以下内在的foreach

foreach(var innerCur in cur)
{
  System.Console.Write(innerCur);
}

 foreach (var innerCur in cur)
 {
   if(innerCur is c1)
      System.Console.Write((innerCur as c1).num);
   else if(innerCur is c2)
      System.Console.Write((innerCur as c2).num);
   else
      System.Console.Write((innerCur as c3).num);
 }

1 个答案:

答案 0 :(得分:0)

一个有趣的问题。我能想到的唯一解决方案是在Generic Repository类中使用反射来调用已传入的泛型Type上的方法。

通过让库的使用者编写一个与他们正在查询的DataBase和Tables相匹配的类来解决问题,包括将数据行转换为对象的函数以及由该函数填充的List。

用户将此对象传递给GetData方法,并由结果填充。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace ThierCode
{
    public class MyTableQuery : YourLibrary.IMultiTableQuery
    {

        public Dictionary<string, string> MethodNameAndSql { get; set; }

        public void PopulateMyObjects(IDataRecord dr)
        {
            MyObject o = new MyObject();
            o.Name = dr["Name"].ToString();
            this.MyObjects.Add(o);
        }

        public List<MyObject> MyObjects { get; set; }
    }

    public class MyObject
    {
        public string Name { get; set; }
    }
}

namespace YourLibrary
{
    public interface IMultiTableQuery
    {
        public Dictionary<string, string> MethodNameAndSql { get; set; }
    }
    public class Repo<T> where T : IMultiTableQuery
    {
        public void GetData(T inputClass)
        {
            Type type = typeof(T);


            foreach (var kvp in inputClass.MethodNameAndSql)
            {
                string sql = kvp.Value;
                //run sql and get datareader

                //get the populate method back from the dictionary 
                MethodInfo methodInfo = type.GetMethod(kvp.Key);
                while (reader.Read())
                {
                    // execute via reflection
                    methodInfo.Invoke(inputClass, reader);
                }

            }
        }

    }
}