【问题标题】:how to create a generic method with optional generic parameter in c#如何在 C# 中创建具有可选泛型参数的泛型方法
【发布时间】:2019-06-20 10:43:41
【问题描述】:

我在 c# 中创建了一个带有 out 参数的泛型方法。它将返回我传递给列表对象的两个输出参数值。

public void ExecuteList<T, T1>(out List<T> obj, out List<T1> obj1, string sql, params object[] parameters) where T : class
{
    using (var db = _context)
    {
        var cmd = db.Database.Connection.CreateCommand();
        cmd.CommandText = sql;
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddRange(parameters);
        try
        {
            db.Database.Connection.Open();
            using (var reder = cmd.ExecuteReader())
            {
                obj = ((IObjectContextAdapter)db).ObjectContext.Translate<T>(reder).ToList();
                reder.NextResult();
                obj1 = ((IObjectContextAdapter)db).ObjectContext.Translate<T1>(reder).ToList();
            }
        }
        finally
        {
            db.Database.Connection.Close();
            cmd.Dispose();
        }
    }
} 

调用这个方法

List<SqlParameter> parameterList = new List<SqlParameter>(); 
parameterList.Add(new SqlParameter("@pageNo", 1));
parameterList.Add(new SqlParameter("@pageSize", 5)); 
SqlParameter[] parameters = parameterList.ToArray();
List<PostModel> PostList = new List<PostModel>();
List<Tag> TagList = new List<Tag>();
Uow.ExecuteList<PostModel,Tag>(out PostList, out TagList, "[dbo].[sp_getdata]", parameters); 

这里我传递 postmodel 和 tag 类进行转换,还传递了两个输出参数 PostList 和 TagList 作为结果。 它将返回完美的结果。 但我的要求是这些转换类和输出参数应该是可选的。 像这样: 当我想要一个结果时,然后传递一个转换类和一个 Out 参数。

List<SqlParameter> parameterList = new List<SqlParameter>();
parameterList.Add(new SqlParameter("@pageNo", 1));
parameterList.Add(new SqlParameter("@pageSize", 5)); 
SqlParameter[] parameters = parameterList.ToArray();
List<PostModel> PostList = new List<PostModel>(); 
Uow.ExecuteList<PostModel>(out PostList, "[dbo].[sp_getdata]", parameters);  

当我想要两个 Result 然后传递两个强制转换类和两个输出参数。

List<SqlParameter> parameterList = new List<SqlParameter>();
parameterList.Add(new SqlParameter("@pageNo", 1));
parameterList.Add(new SqlParameter("@pageSize", 5)); 
SqlParameter[] parameters = parameterList.ToArray();
List<PostModel> PostList = new List<PostModel>();
List<Tag> TagList = new List<Tag>();
Uow.ExecuteList<PostModel,Tag>(out PostList, out TagList, "[dbo].[sp_getdata]", parameters);  

请帮我解决我的问题

【问题讨论】:

  • 您正在尝试复制实体框架已经提供的内容。您使用的是哪个 EF 版本?问题在于首先尝试使用普通的旧 ADO.NET 和映射。已经有一些方法可以将存储过程结果映射到实体。
  • 这看起来像XY problem。您有一个问题X(如何将存储过程映射到实体)并假设Y 是解决方案(编写普通的旧ADO.NET 代码)。当您遇到问题(很多映射所需的手动代码)时,您会询问 Y,而不是实际问题,X
  • 这段代码还有其他严重的问题——它将1 作为@pageNo 类型的type 传递。这段代码中调用的构造函数是SqlParameter(string,SqlDbType )。那是因为枚举本质上是整数。此外,paging 已经可以通过例如Products.....Skip().Take() 获得

标签: c# .net generics optional-parameters generic-list


【解决方案1】:

您可以创建多个调用相同私有方法的重载:

private void Execute<T, T1>(ref List<T> obj, ref List<T1> obj1, string sql, params object[] parameters) where T : class
{
    using (var db = _context)
    {    
        var cmd = db.Database.Connection.CreateCommand();
        cmd.CommandText = sql;
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddRange(parameters);
        try
        {
            db.Database.Connection.Open();
            using (var reader = cmd.ExecuteReader())
            {
                obj = ((IObjectContextAdapter)db).ObjectContext.Translate<T>(reader).ToList();
                if(obj1 != null) {
                    reader.NextResult();
                    obj1 = ((IObjectContextAdapter)db).ObjectContext.Translate<T1>(reader).ToList();
                }                
            }
        }
        finally
        {
            db.Database.Connection.Close();
            cmd.Dispose();
        }
    }
}

public void ExecuteList<T, T1>(out List<T> obj, out List<T1> obj1, string sql, params object[] parameters) where T : class
{
    obj = new List<T>();
    obj1 = new List<T1>();
    Execute(ref obj, ref obj1, sql, parameters);
}

public void ExecuteList<T>(out List<T> obj, string sql, params object[] parameters) where T : class
{
    obj = new List<T>();
    List<object> stub = null;//generic argument doesn't matter because it will not be used
    Execute<T, object>(ref obj, ref stub, sql, parameters);
} 

请注意,我的第一个方法是私有的,只能从公共重载中调用(可以添加任意数量的输出参数/重载)。

也可能将T1 限制为class 并使用List&lt;SqlParameter&gt; 而不是params object[] parameters 作为最后一个参数是有意义的。

【讨论】:

  • EF 已经提供了将存储过程映射到实体的方法。
  • 这对我没用,因为我不想重载方法。如果可能的话,请给我任何没有重载方法的解决方案。并且所有参数都应该是可选的。
  • 我认为不可能
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多