我正在使用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);
}
通过以上示例,是否有推荐的处理方法?像这样的铸造会损害性能吗?谢谢!
答案 0 :(得分:2)
使用dynamic
时,即使作为参数,整个表达式也是通过动态绑定处理的,并且会在编译时产生“动态”(因为它基于其运行时类型)。这包含在C#规范的7.2.2中:
但是,如果表达式是动态表达式(即具有动态类型),则表示它所参与的任何绑定都应基于其运行时类型(即它在运行时表示的对象的实际类型)时间)而不是它在编译时的类型。因此,这种操作的绑定被推迟到在程序运行期间执行操作的时间。这被称为动态绑定。
在您的情况下,使用强制转换可以安全地将其转换为IEnumerable<StringBuilder>
,并且对性能的影响非常小。 example2
版本的效率略高于example3
版本,但是当以这种方式使用时,两者的开销都很小。
答案 1 :(得分:1)
虽然我不能很好地说出“为什么”,但我认为你应该能够将example1写成:
IEnumerable<StringBuilder> example1 = dynamicObjects.Select<dynamic, StringBuilder>(s => makeStringBuilder(s));
你需要告诉编译器投影应该采用什么类型,但我确信其他人可以澄清为什么它无法推断出正确的类型。但我相信通过指定投影类型,您可以避免必须实际投射,这应该会产生一些性能优势。