jsh*_*all 20 c# foreach extension-methods
我试图使一些代码更具可读性.例如foreach(var row in table) {...}而不是foreach(DataRow row in table.Rows) {...}.
为此,我创建了一个扩展方法:
namespace System.Data {
public static class MyExtensions {
public static IEnumerable<DataRow> GetEnumerator( this DataTable tbl ) {
foreach ( DataRow r in tbl.Rows ) yield return r;
}
}
}
Run Code Online (Sandbox Code Playgroud)
但编译器仍然抛出foreach statement cannot operate on variables of type 'System.Data.DataTable' because 'System.Data.DataTable' does not contain a public definition for 'GetEnumerator'.
为了确认我正确实现了扩展方法,我尝试了以下代码,编译器没有问题.
for ( IEnumerator<DataRow> enm = data.GetEnumerator(); enm.MoveNext(); ) {
var row = enm.Current;
...
}
Run Code Online (Sandbox Code Playgroud)
在您说它是因为IEnumerator或未IEnumerator<DataRow>实现之前,请考虑以下内容进行编译:
public class test {
public void testMethod() {
foreach ( var i in new MyList( 1, 'a', this ) ) { }
}
}
public class MyList {
private object[] _list;
public MyList( params object[] list ) { _list = list; }
public IEnumerator<object> GetEnumerator() { foreach ( var o in _list ) yield return o; }
}
Run Code Online (Sandbox Code Playgroud)
Eri*_*ert 41
到目前为止,其他答案中存在许多混淆.(虽然Preston Guillot的答案非常好,但实际上并没有指出这里发生的事情.)让我试着澄清一下.
首先,你只是运气不好.C#要求foreach语句中使用的集合:
GetEnumerator与所需模式匹配的公共.IEnumerable(当然,IEnumerable<T>要求IEnumerable)结果是集合类型必须实际实现这种GetEnumerator或那种方式.提供扩展方法不会削减它.
这很不幸.在我看来,当C#团队的补充扩展方法,C#3,他们应该修改现有的功能,如foreach(甚至using!)考虑扩展方法.但是,在C#3发布周期中,时间表非常紧张,并且任何未及时实现LINQ的额外工作项都可能被削减.我不记得设计团队在这一点上说了什么,我再也没有笔记了.
这种不幸的情况是语言成长和发展的结果; 旧版本是为他们的时间需求而设计的,新版本必须在此基础上构建.如果,反事实地,C#1.0有扩展方法和泛型,那么foreach循环可以像LINQ一样设计:作为简单的句法转换.但事实并非如此,现在我们仍然坚持预先通用的预扩展方法设计.
其次,在其他答案和评论中似乎存在一些错误的信息,这些答案和评论是关于准确foreach工作所需要的.您无需实施IEnumerable.有关这个常被误解的功能的更多详细信息,请参阅我关于此主题的文章.
第三,关于这种行为是否实际上是由规范证明是合理的,似乎存在一些问题.它是.规范没有明确地指出在这种情况下不考虑扩展方法,这是不幸的.但是,规范非常清楚会发生什么:
该编译器开始做一个成员查找的GetEnumerator.成员查找算法在7.3节中详细记录,成员查找不考虑扩展方法,只考虑实际成员.仅在常规重载解析失败后才考虑扩展方法,并且我们还没有达到过载解决方案.(是的,扩展方法由成员访问考虑,但成员访问和成员查找是不同的操作.)
如果成员查找无法找到方法组,则尝试匹配该模式将失败.因此编译器永远不会继续算法的重载解析部分,因此永远不会有机会考虑扩展方法.
因此,您描述的行为与指定的行为一致.
如果您想要准确理解编译器如何分析语句,我建议您仔细阅读规范的第8.8.4节foreach.
第四,我鼓励您花时间以其他方式为您的计划增加价值.令人信服的好处
foreach (var row in table)
Run Code Online (Sandbox Code Playgroud)
过度
foreach(var row in table.Rows)
Run Code Online (Sandbox Code Playgroud)
对开发人员来说很小,对客户来说是不可见的.花时间添加新功能或修复错误或分析性能,而不是将已经完全清晰的代码缩短五个字符.
| 归档时间: |
|
| 查看次数: |
17974 次 |
| 最近记录: |