2013-04-12 8 views
8

Quando si tenta di utilizzare il metodo Enumerable.Count() estensione da Visual Basic, il codice seguente genera un errore in fase di compilazione:Come specificare Enumerable.Count() anziché 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 

L'errore prodotto è:

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

ho scelto come target .NET 4.0, quindi i metodi di estensione dovrebbero essere supportati. Vale anche la pena notare che il codice equivalente in C# deduce correttamente il metodo di estensione ...

Perché il compilatore non è in grado di dedurre l'uso di Enumerable.Count, dato il predicato che sto passando come argomento, e come can Uso il metodo di estensione anziché la proprietà Count di Elenco?

risposta

1

Per rispondi alla tua domanda su perché il VB non può fare ciò che C# può in questo caso ...

VB consente di accedere alle proprietà con () dopo il nome e consente inoltre di chiamare funzioni senza parametri omettendo lo (). Anche gli indicizzatori usano parentesi tonde, invece di parentesi quadre che hai in C#. Questi sono esempi di straordinarie funzionalità di VB progettate per semplificare la programmazione, che in realtà risulta in un codice più ambiguo, più difficile da capire e soggetto a bug.

Quindi, in questo caso particolare, VB vede che si sta accedendo a Conteggio e assume le parentesi dopo che è un indicizzatore della proprietà Count, anziché gli argomenti della funzione Count.

C# vede le parentesi tonde e si rende conto che non si sta accedendo all'indicizzatore, si deve chiamare una funzione, quindi cerca una funzione.

Ovviamente, c'è anche spazio per l'ambiguità in C#. Ad esempio, una proprietà con lo stesso nome di un metodo di estensione, che restituisce un tipo delegato sarà chiamato a preferenza il metodo di estensione ...

public Action Count { get; set; } 

Ah ... giorni felici.

Su come chiamare la funzione IEnumerable.Count(), un getto (preferibilmente DirectCast()) o eseguendo il metodo di estensione direttamente Enumerable.Count(...), è di gran lunga preferibile creare una nuova matrice di chiamare contare su ...!

2

Non sono sicuro del motivo per cui non si ottiene il sovraccarico come opzione, ma si dovrebbe essere in grado di trasmettere l'elenco a IEnumerable(Of Foo) a questo punto il compilatore non consentirà più la proprietà List(Of Foo).Count.

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

+1 Questa tecnica funziona, ma ho ancora fame di sapere * perché * VB non può dedurre le mie intenzioni mentre C# può ... –

1

Se l'elenco viene convertito in un array funziona

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

Il compilatore VB.Net cerca prima di cercare Count nell'istanza List, e trova la proprietà Count. Questa proprietà viene utilizzata al posto del metodo di estensione poiché i campi e le proprietà utilizzano sempre i metodi di estensione shadow per nome. Non so dove ciò sia specificato in Visual specifiche di base lingue, ma si può leggere di più in questa MSDN Magazin article:

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.

Quindi, Count(Function(foo) foo.Bar = "a") potrebbe significare: chiamare il Count -property con Function(foo) foo.Bar = "a", o prendere il risultato del Count -proprietà e indicizzarlo con Function(foo) foo.Bar = "a", che potrebbe essere totalmente valido, poiché le proprietà indicizzate in VB.Net possono assumere qualsiasi parametro.

Questo funziona in C# (credo) perché è più semplice per il compilatore C# distinguere tra chiamate di metodo e un accesso di proprietà, perché diversamente da VB.Net C# non consente parametri arbitrari su proprietà e proprietà indicizzate.


Per utilizzare il metodo di estensione, si chiama come si farebbe chiamare ogni metodo diverso statico (comune):

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

o chiamare Call su IEnumerable esplicitamente:

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