- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
不久前我发现了新的dynamic
关键字不适用于 C# 的 foreach
陈述:
using System;
sealed class Foo {
public struct FooEnumerator {
int value;
public bool MoveNext() { return true; }
public int Current { get { return value++; } }
}
public FooEnumerator GetEnumerator() {
return new FooEnumerator();
}
static void Main() {
foreach (int x in new Foo()) {
Console.WriteLine(x);
if (x >= 100) break;
}
foreach (int x in (dynamic)new Foo()) { // :)
Console.WriteLine(x);
if (x >= 100) break;
}
}
}
dynamic
变量应该完全像在编译时知道集合变量的类型一样工作。我发现第二个循环在编译时实际上是这样的:
foreach (object x in (IEnumerable) /* dynamic cast */ (object) new Foo()) {
...
}
x
的 foreach 语句中的类型 - 这对我来说有点令人惊讶......而且,C# 编译器完全忽略了来自动态类型变量的集合可能实现
IEnumerable<T>
界面!
foreach
C# 4.0 规范
中描述了语句行为。 8.8.4 foreach 语句文章。
CSharpBinderFlags.ForEachCast
标志,将发出的代码更正为:
foreach (int x in (IEnumerable<int>) /* dynamic cast with the CSharpBinderFlags.ForEachCast flag */ (object) new Foo()) {
...
}
CSharpConvertBinder
添加一些额外的逻辑:
IEnumerable
收藏和IEnumerator
到IEnumerable<T>
/IEnumerator<T>
. Ienumerable<T>
/IEnumerator<T>
来实现这个接口(interface)。 foreach
语句迭代
dynamic
与迭代静态已知的集合变量完全不同,完全忽略用户指定的类型信息。所有这些结果都是由于不同的迭代行为(
IEnumarble<T>
-实现集合被迭代为仅
IEnumerable
-实现)和超过
150x
迭代时减速
dynamic
.简单的修复将产生更好的性能:
foreach (int x in (IEnumerable<int>) dynamicVariable) {
dynamic
如果在编译时知道类型,则工作方式完全相同,但很遗憾看到
dynamic
在 IT CAN 与静态类型代码相同的情况下,其工作方式完全不同。
foreach
超过
dynamic
作品不同于
foreach
超过别的?
最佳答案
首先,向对这个问题感到困惑的读者解释一些背景:C#语言实际上并不要求“foreach”的集合实现IEnumerable
.相反,它要求实现 IEnumerable
,或者它实现了IEnumerable<T>
,或者只是它有一个 GetEnumerator 方法(并且 GetEnumerator 方法返回的内容具有 Current 和 MoveNext 与预期的模式相匹配,依此类推。)
对于像 C# 这样的静态类型语言来说,这似乎是一个奇怪的特性。我们为什么要“匹配模式”?为什么不要求集合实现 IEnumerable?
想想泛型之前的世界。如果你想创建一个整数集合,你必须使用 IEnumerable。因此,对 Current 的每次调用都会将一个 int 装箱,然后调用者当然会立即将其拆箱回 int。这很慢并且会对 GC 造成压力。通过使用基于模式的方法,您可以在 C# 1.0 中创建强类型集合!
现在当然没有人实现这种模式。如果你想要一个强类型集合,你实现 IEnumerable<T>
你就完成了。如果 C# 1.0 可以使用泛型类型系统,那么“匹配模式”功能就不太可能首先实现。
正如您所指出的,为 foreach 中的动态集合生成的代码不是寻找模式,而是寻找到 IEnumerable 的动态转换(然后将 Current 返回的对象转换为循环变量的类型当然。)所以你的问题基本上是“为什么使用动态类型作为 foreach 的集合类型生成的代码无法在运行时查找模式?”
因为现在已经不是 1999 年了,即使回到 C# 1.0 时代,使用该模式的集合也几乎总是实现 IEnumerable。真正的用户将编写生产质量的 C# 4.0 代码,对实现该模式但不实现 IEnumerable 的集合执行 foreach 的可能性极低。现在,如果您处于这种情况,那是出乎意料的,很抱歉我们的设计未能预测到您的需求。如果您认为您的场景实际上很常见,并且我们误判了它的罕见程度,请发布有关您的场景的更多详细信息,我们将考虑为假设的 future 版本更改此内容。
请注意,我们生成到 IEnumerable 的转换是动态转换,而不仅仅是类型测试。这样,动态对象可以参与;如果它没有实现 IEnumerable 但希望提供一个代理对象,它可以自由地这样做。
简而言之,“动态 foreach”的设计是“动态地向对象请求一个 IEnumerable 序列”,而不是“动态地做我们在编译时会做的每一个类型测试操作”。这在理论上确实巧妙地违反了动态分析给出与静态分析相同的结果的设计原则,但在实践中,这是我们期望绝大多数动态访问的集合工作的方式。
关于dynamic - C# 4.0 'dynamic' 和 foreach 语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2939024/
这是一个假设性问题。如果我有来自 3 个单独的 sql db 查询的 3 个数组,这些查询都与另一个数组相关。例如…… //db schools id | school_name classes id
在我的应用程序中,我使用 scrape(string url) 方法从网页中抓取链接。可以说它每次都返回我 10 个 url。 我想从每个抓取的 url 中抓取 10 个链接。 长话短说: (第 1
我的java7代码: final Map result = new HashMap<>(); final Set> classes = getClasses(co.glue()); for (fina
是否可以在 SwiftUI 中设置变量,例如在这样的 ForEach 中: struct ContentView: View { var test: Int var body: som
在 D、int、uint 中使用 foreach 时,循环索引的首选类型是什么?或者只是通过省略类型自动实现? 最佳答案 一般来说,索引应该是size_t。与长度相同。如果您尝试使用 int 或 ui
根据 http://dlang.org/statement.html 的“Foreach 限制”部分以下代码 int[] a; int[] b; foreach (int i; a) { a
在什么情况下我们应该在 JDK 8 中使用旧的 foreach 循环遍历新的 collection.forEach() 还是最好的做法是转换 every foreach 循环?是否存在任何重要的性能差
获得类似东西的惯用方法是什么? ((fn [coll] (function-body)) [:a :b :c :d]) -> [[:a :b][:a :c][:a :d][:b :c][:b :d][
我正在创建一个基于 who is it? 的 Java 应用程序。现在我正在制作一种方法,在回答问题时我需要其他卡片。 我有两个列表: 列表是一个 ImageView 列表,其中我有卡片必须代表的 2
我希望有人能在我发疯之前帮助我。 我有 3 张 table : Table A SELECT companypk, companyname, logo, msscope FROM global_com
我正在尝试将多个字符串添加到 C# 中的 MailAddress。 如果我使用ForEach,我的代码会是这样 foreach (var item in GetPeopleList()
我没有太多的 C# 经验,所以如果有人能指出正确的方向,我将不胜感激。我有一个引用对象变量的 foreach 循环。我希望在主循环中创建另一个 foreach 循环,将当前变量与对象数组中的其余变量进
下面的代码每 60 秒删除文件夹“Images”中的文件,它可以工作,但是当文件夹为空时它会显示:警告:为 foreach() 提供的参数无效如果没有文件,如何解决这个问题,说“文件夹为空而不是那个警
我需要在两种不同的模式下运行,因此“if”(第二个稍后构建一个大的 csv) 下面对于单个实例运行正常,但在第二个 (*) 的加载时间上失败,因为在前 7k 行中的每一行上运行。 我想避免可怕的事情
我们可以使用以下两种方法实现类数组对象的迭代: let arrayLike = document.getElementsByClassName('dummy'); [].forEach.call(ar
我有这个代码 ... 它说: Attribute value invalid for tag forEach according to TLD 最佳答案 forEach标签不支持 valu
我在 SwiftUI 中有一个像这样的 ForEach: ForEach(entries) { (e: MyType) in NavigationLinkItem(entry: e) } 现在我
我无法在一个 Foreach 或 Foreach-Object 循环中使用多个命令 我的情况是—— 我有很多文本文件,大约 100 个。 所以他们被阅读 Get-ChildItem $FilePath
我必须从 json 文件(实际上是 2 个 json 文件)执行 ForEach,因此我执行 2 forEach,代码是 table { font-family: arial, sans-
我对编程很陌生,当我执行 forEach 函数时,我的应用程序返回错误。我的controller.js中有以下代码 $scope.ajaxRequest = A.Game.get({action: '
我是一名优秀的程序员,十分优秀!