3

我正在使用 Dapper 返回动态对象,有时还手动映射它们。一切正常,但我想知道铸造法则是什么以及为什么以下示例成立。

(对于这些示例,我使用“StringBuilder”作为我的已知类型,尽管它通常类似于“Product”)

IEnumerable<dynamic>示例 1:即使 'makeStringBuilder' 清楚地返回一个StringBuilder对象,为什么这会返回一个?

示例 2:为什么会构建,但如果是 'Example1' 则不会IEnumerable<StringBuilder>

示例 3:与示例 2 相同的问题?

private void test()
    {
        List<dynamic> dynamicObjects = {Some list of dynamic objects};

        IEnumerable<dynamic> example1 = dynamicObjects.Select(s => makeStringBuilder(s));

        IEnumerable<StringBuilder> example2 = dynamicObjects.Select(s => (StringBuilder)makeStringBuilder(s));

        IEnumerable<StringBuilder> example3 = dynamicObjects.Select(s => makeStringBuilder(s)).Cast<StringBuilder>();

    }

    private StringBuilder makeStringBuilder(dynamic s)
    {
        return new StringBuilder(s);
    }

对于上述示例,是否有推荐的处理方法?这样的选角会影响表演吗?谢谢!

4

2 回答 2

2

当您使用 时dynamic,即使作为参数,整个表达式也是通过动态绑定处理的,并将导致在编译时是“动态的”(因为它基于其运行时类型)。这在 C# 规范的 7.2.2 中有所介绍:

但是,如果表达式是动态表达式(即具有动态类型),则表明它参与的任何绑定都应基于其运行时类型(即它在运行时表示的对象的实际类型),而不是比它在编译时的类型。因此,这种操作的绑定被推迟到程序运行期间要执行该操作的时间。这称为动态绑定。

在您的情况下,使用强制转换将安全地将其转换为IEnumerable<StringBuilder>,并且对性能的影响应该很小。该example2版本的效率略高于该example3版本,但以这种方式使用时,两者的开销都非常小。

于 2012-10-02T19:39:06.143 回答
1

虽然我不能很好地说明“为什么”,但我认为您应该能够将 example1 写为:

IEnumerable<StringBuilder> example1 = dynamicObjects.Select<dynamic, StringBuilder>(s => makeStringBuilder(s));

您需要告诉编译器投影应该采用什么类型,尽管我确信其他人可以澄清为什么它不能推断出正确的类型。但我相信通过指定投影类型,您可以避免实际投射,这应该会产生一些性能优势。

于 2012-10-02T20:00:14.760 回答