Dan*_*n J 9 vb.net extension-methods
尝试从Visual Basic 使用Enumerable.Count()扩展方法时,以下代码导致编译时错误:
Imports System.Linq
Module Module1
Sub Main()
Dim l As New List(Of Foo) From {New Foo("a"), New Foo("b"), New Foo("a")}
Dim i As Integer = l.Count(Function(foo) foo.Bar = "a")
Console.WriteLine(i)
Console.ReadLine()
End Sub
Class Foo
Sub New(ByVal bar As String)
Me.Bar = bar
End Sub
Public Property Bar As String
End Class
End Module
Run Code Online (Sandbox Code Playgroud)
产生的错误是:
'Public ReadOnly Property Count As Integer'没有参数,其返回类型无法编入索引.
我的目标是.NET 4.0,因此应该支持扩展方法.值得注意的是,C#中的等效代码正确地推断了扩展方法......
为什么编译器无法推断出使用Enumerable.Count的,因为我是作为参数传递的谓词,以及如何能我使用扩展方法,而不是名单的Count属性?
该VB.Net编译器首先尝试查找Count的List实例,它找到的Count财产.由于字段和属性始终按名称影子扩展方法,因此使用此属性代替扩展方法.我不知道在Visual Basic语言规范中说明了哪些内容,但您可以在此MSDN杂志文章中阅读更多内容:
字段和属性始终按名称影子扩展方法.图4显示了具有相同名称和各种调用的扩展方法和公共字段.虽然扩展方法包含了第二个参数,字段阴影的名字,并使用该名称结果访问该领域的所有呼叫的扩展方法.各种重载调用将所有编译,但在运行时,其结果可能是出乎意料的,因为他们会绑定到属性,并使用默认属性的行为,以返回单个字符或导致运行时异常.选择扩展方法的名称非常重要,这样可以避免与属性,字段和现有实例方法发生冲突.
因此,Count(Function(foo) foo.Bar = "a")可能意味着:调用Count-property Function(foo) foo.Bar = "a",或者获取-property 的结果Count并将其索引Function(foo) foo.Bar = "a",这可能是完全有效的,因为VB.Net中的索引属性可以采用任何参数.
这适用于C#(我猜),因为C#编译器更容易区分方法调用和属性访问,因为与VB.Net不同,C#不允许在属性和索引属性上使用任意参数.
要使用扩展方法,您可以像调用其他所有静态(共享)方法一样调用它:
Dim i As Integer = Enumerable.Count(l, Function(foo) foo.Bar = "a")
Run Code Online (Sandbox Code Playgroud)
或致电Call上IEnumerable明确:
Dim i As Integer = l.AsEnumerable().Count(Function(foo) foo.Bar = "a")
Run Code Online (Sandbox Code Playgroud)
回答你的问题,为什么VB不能做 C# 在这种情况下可以做的事情......
VB 允许您访问()名称后带有 的属性,还允许您通过省略(). 此外,索引器使用圆括号,而不是 C# 中的方括号。这些是 VB 的巨大功能的示例,这些功能旨在使编程变得更容易,但实际上会导致代码更加模糊、难以理解且容易出现错误。
因此,在这种特殊情况下,VB 看到您正在访问 Count,并假定其后面的括号是 Count 属性的索引器,而不是 Count 函数的参数。
C# 看到圆括号,并意识到您没有访问索引器,您必须调用一个函数,因此会查找一个函数。
当然,C# 中也存在歧义的地方。例如,与扩展方法同名的属性将优先于扩展方法被调用,该属性返回委托类型...
public Action Count { get; set; }
Run Code Online (Sandbox Code Playgroud)
啊……幸福的日子。
至于如何调用 IEnumerable.Count() 函数,强制转换(最好DirectCast())或直接执行扩展方法Enumerable.Count(...),比创建一个全新的数组来调用 count 要好得多......!