使用 func<> 委托时,我可以以任何方式更改签名吗?

Posted

技术标签:

【中文标题】使用 func<> 委托时,我可以以任何方式更改签名吗?【英文标题】:Can I vary the signature in any way when using the func<> delegate? 【发布时间】:2012-08-14 19:32:04 【问题描述】:

我有一个数据访问层命名空间,其中包含大量重复代码(主要是设置命令对象并执行存储过程以返回添加到列表中的数据集)。我正在尝试编写一个返回List&lt;T&gt; 的通用工厂方法。我对泛型和委托都比较陌生。我的想法是有一个 Func 参数来创建添加到List&lt;T&gt; 的对象。它将在通常的while dataReader.Read() 块内调用。我的问题是,我将使用的数据集具有不同数量的列。

这是我目前所拥有的:

private static List<T> ListFromDatabase<T,U>(String CommandName, SqlConnection SqlConn, Func<T,U> CreateListObj, 
    List<SqlParameter> ParamList = null)

    List<T> returnList = new List<T>();

    using (SqlCommand cmd = new SqlCommand(CommandName,SqlConn))
    
        cmd.CommandType = CommandType.StoredProcedure;
        foreach (SqlParameter sp in ParamList)
        
            if (sp.Value == null)
                sp.Value = DBNull.Value;
            cmd.Parameters.Add(sp);
        

        SqlDataReader sdr = cmd.ExecuteReader();
        while (sdr.Read())
        
            returnList.Add(CreateListObj);
        
    

    return returnList;

以我目前的理解水平,这可能是不可能的,因为我可能不得不针对不同数量的参数改变 Func 签名。这是可行的还是接近的?如果不是,我愿意采用不同的方法,如果有人可以提供帮助。非常感谢提前..

更新:这正是我想要的:

Convert rows from a data reader into typed results

【问题讨论】:

我会做类似你所提议的事情。我想知道,您对实施过程中的哪些方面不满意? @BrianDishaw 我不知道如何“充实”/实现 func 委托,尤其是因为 #of 参数会有所不同.. U 类型参数有什么用?这不会编译,因为您试图将Func&lt;T, U&gt; 添加到List&lt;T&gt;。听起来您想要一个Func&lt;SqlDataReader, T&gt; 并将读者传递给函数以创建和水合T 的实例? @Lee Yup,不会编译,这就是我卡住的地方.. 我知道 U 目前下落不明.. 你的建议很接近,但我会必须在为委托传递的函数中进行迭代,我希望在工厂中发生的迭代中调用委托。 @StatsViaCsh - 迭代将在 ListFromDatabase 方法中发生:while(sdr.Read()) returnList.Add(func(sdr)); 【参考方案1】:

为什么不将您的SqlDataReader 作为IDataRecord 传递给您的代表?委托可以从数据记录中得到它所需要的;您可以控制对阅读器的迭代。

【讨论】:

我不熟悉 IDataRecord。现在调查一下,谢谢。【参考方案2】:

最优雅的方法是通过传递一个函数来指定 T 为 Tuple&lt;T1,T2,T3...&gt;,该函数接受具有特定数量和类型的项目的元组,然后使用 Tuple.Create 使用sdr 中一行的内容。问题是,当从 DataReader 中获取字段时,它们会作为未确定类型的对象出现,而当您不知道它们的真实类型时传递它们的最安全方法是作为字符串,这意味着 CreateListObj 函数必须期望字符串和能够正确解析它们(因此期望元组中的特定列顺序)。

【讨论】:

【参考方案3】:

我过去所做的是定义“构建器”方法,该方法采用 IDataReader 并返回它们所定义类型的对象(我将它们作为泛型类的方法,而不是比代表,但Func&lt;IDataReader, T&gt; 会做同样的事情。

一般来说,我在ExecuteReader 调用中使用了CommandBehavior.CloseConnection,然后返回了一个保存在阅读器上的类,实现了IEnumerable&lt;T&gt;,然后在处理阅读器时关闭了阅读器(并因此关闭了底层连接)而不是首先创建一个完整的列表(如果枚举器实际上根本没有枚举,你必须小心它会被清理)。

优点是我不必在定义时担心列号和类型的差异,只需在实现时(我不禁担心)。

【讨论】:

有趣的方法,我不知道我是否可以完全按照您的描述实现它,但我会尝试一下。

以上是关于使用 func<> 委托时,我可以以任何方式更改签名吗?的主要内容,如果未能解决你的问题,请参考以下文章

C# Action<T;和 Func<T;委托

将 Func 委托与 Async 方法一起使用

c# 使用运行时泛型类型调用委托

Func<string,string> 和委托有啥区别?

浅谈C#中常见的委托<Func,Action,Predicate>(转)

如何在 WCF 中使用 DataContract/DataMember 序列化 Func<int, int>(甚至是一般委托)类型字段