为什么使用Linq的.Select()返回IEnumerable <dynamic>,即使类型是明确定义的?</dynamic>

时间:2012-10-02 19:26:32

标签: linq dynamic casting dapper

我正在使用Dapper返回动态对象,有时还会手动映射它们。一切都运转良好,但我想知道铸造的规律是什么以及下面的例子为什么成真。

(对于这些例子,我使用'StringBuilder'作为我的已知类型,尽管它通常类似'产品')

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

示例2:为什么要构建,但如果是IEnumerable<StringBuilder>则不会出现“Example1”?

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

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);
    }

通过以上示例,是否有推荐的处理方法?像这样的铸造会损害性能吗?谢谢!

2 个答案:

答案 0 :(得分:2)

使用dynamic时,即使作为参数,整个表达式也是通过动态绑定处理的,并且会在编译时产生“动态”(因为它基于其运行时类型)。这包含在C#规范的7.2.2中:

  

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

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

答案 1 :(得分:1)

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

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

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