2013-04-12 24 views
8

Khi cố gắng để sử dụng phương pháp Enumerable.Count() mở rộng từ Visual Basic, kết quả mã sau vào một lỗi thời gian biên dịch:Làm cách nào để chỉ định Enumerable.Count() thay cho List.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 

Các lỗi được sản xuất là:

'Public ReadOnly Property Count As Integer' has no parameters and its return type cannot be indexed.

Tôi đang nhắm mục tiêu NET 4.0, vì vậy các phương thức khuyến nông nên được hỗ trợ. Nó cũng đáng chú ý là mã tương đương trong C# đưa vào phương thức mở rộng một cách chính xác ...

Tại sao trình biên dịch không thể suy ra việc sử dụng Enumerable.Count, cho biến vị ngữ tôi đi qua làm đối số và cách có thể Tôi sử dụng phương thức mở rộng thay vì thuộc tính Đếm của Danh sách không?

Trả lời

1

Để trả lời câu hỏi của bạn là lý do tại sao VB không thể làm những gì C# có thể trong trường hợp này ...

VB cho phép bạn truy cập các thuộc tính với () sau tên và cũng cho phép bạn gọi các hàm không có tham số bằng cách bỏ qua (). Các chỉ mục cũng sử dụng các dấu ngoặc tròn, thay vì các dấu ngoặc vuông mà bạn có trong C#. Đây là những ví dụ về các tính năng VB to lớn được thiết kế để giúp lập trình dễ dàng hơn, điều này thực sự dẫn đến mã dễ bị mơ hồ, khó hiểu hơn và dễ bị lỗi hơn.Vì vậy, trong trường hợp cụ thể này, VB thấy bạn đang truy cập Đếm, và giả định các dấu ngoặc sau khi nó là một người lập chỉ mục đến thuộc tính Đếm, thay vì các đối số cho hàm Đếm.

C# xem các dấu ngoặc tròn và nhận ra rằng bạn không truy cập vào trình chỉ mục, bạn phải gọi một hàm, vì vậy hãy tìm một hàm.

Tất nhiên, cũng có chỗ cho sự mơ hồ trong C#. Ví dụ: thuộc tính có cùng tên với một phương thức tiện ích mở rộng sẽ trả về loại đại biểu sẽ được gọi theo tùy chọn phương thức mở rộng ...

public Action Count { get; set; } 

Ah ... happy days.

Cách gọi hàm IEnumerable.Count(), một dàn diễn viên (tốt nhất là DirectCast()) hoặc thực hiện phương pháp mở rộng trực tiếp Enumerable.Count(...), được ưa chuộng hơn nhiều để tạo một mảng hoàn toàn mới để đếm cuộc gọi trên ...!

2

Tôi không chắc chắn lý do tại sao bạn không nhận được tình trạng quá tải dưới dạng tùy chọn, nhưng bạn có thể truyền danh sách sang IEnumerable(Of Foo) vào thời điểm đó trình biên dịch sẽ không cho phép thuộc tính List(Of Foo).Count nữa.

CType(l, IEnumerable(Of Foo)).Count(Function(foo) foo.Bar = "a") 
+0

+1 Kỹ thuật này hoạt động, nhưng tôi vẫn còn đói để biết * tại sao * VB không thể suy ra ý định của tôi trong khi C# có thể ... –

1

Nếu danh sách được chuyển đổi sang một mảng nó hoạt động

Dim l As New List(Of Foo) From {New Foo("a"), New Foo("b"), New Foo("a")} 
    Dim i As Integer = l.ToArray.Count(Function(x) x.Bar = "a") 
7

Trình biên dịch VB.Net đầu tiên cố gắng nhìn lên Count trên List dụ, và nó tìm Count tài sản. Thuộc tính này được sử dụng thay cho phương thức mở rộng vì các trường và thuộc tính luôn luôn sử dụng các phương thức mở rộng theo tên. Tôi không biết nơi này được ghi trong Visual Basic Ngôn ngữ spec, nhưng bạn có thể đọc thêm ở MSDN Magazin article này:

Fields and properties always shadow extension methods by name. Figure 4 shows an extension method and public field with the same name and various calls. Though the extension method contains a second argument, the field shadows the extension method by name and all calls using this name result in accessing the field. The various overloaded calls will all compile, but their results at run time may be unexpected since they will bind to the property and use the default property behavior to return a single character or result in a runtime exception. It is important to choose the names of your extension methods so you avoid clashes with properties, fields, and existing instance methods.

Vì vậy, Count(Function(foo) foo.Bar = "a") có thể có nghĩa: gọi Count -property với Function(foo) foo.Bar = "a", hoặc lấy kết quả của Count -property và lập chỉ mục nó với Function(foo) foo.Bar = "a", có thể hoàn toàn hợp lệ, vì các thuộc tính được lập chỉ mục trong VB.Net có thể lấy bất kỳ tham số nào.

Điều này hoạt động trong C# (tôi đoán) vì trình biên dịch C# dễ phân biệt giữa các cuộc gọi phương thức và quyền truy cập thuộc tính, vì không giống VB.Net C# không cho phép tham số tùy ý trên thuộc tính và thuộc tính được lập chỉ mục.


Để sử dụng phương pháp mở rộng, bạn gọi nó như bạn sẽ gọi tất cả các phương pháp khác tĩnh (chia sẻ):

Dim i As Integer = Enumerable.Count(l, Function(foo) foo.Bar = "a") 

hoặc gọi Call trên IEnumerable một cách rõ ràng:

Dim i As Integer = l.AsEnumerable().Count(Function(foo) foo.Bar = "a")