none
ListクラスでのLINQのCountメソッドがビルドエラー RRS feed

  • 質問

  • VB2013で
    Listクラスで条件を満たす要素数を数えるのに、
    predicateデリゲートを指定したLINQのCountメソッドを使いたいのですが、

    ListクラスのCountプロパティとみなされてビルドエラーになります。
    Whereメソッドを経由させる以外の回避法はないものでしょうか?

    Module Module1
        Sub Main()
            Dim wkList = Enumerable.Range(1, 10).ToList
    
            'predicateデリゲートを使いたいけど、VBだとビルドが通らない
            'Console.WriteLine(wkList.Count(Function(X) X >= 5))
    
            'これだと、ビルドが通るけど、Whereメソッドを経由させたくないなぁ
            Console.WriteLine(wkList.Where(Function(X) X >= 5).Count)
        End Sub
    End Module
    

    2015年12月9日 2:19

回答

  • > 今のところちょっと謎ですね・・・

    trapemiya さんが紹介された MSDN Forum のスレッドで、Matt Warren - MSFT さんが、

    "VB compiler is matching the lists Count property instead of the Enumerable.Count() extension method and the Count property is blocking the visibility of the extension method's other signature."

    Timothy Ng MSFT さんが、

    "in VB, properties shadow methods (and thus, extension methods) by name."

    と書いた説明、即ち VB.NET のコンパイラの問題ということで自分的には納得しているのですが。(公式文書ではないといわれるかもしれませんが)

    質問者さんのコードで wkList は List(Of Int32) 型、List(Of Int32) 型には Count プロパティが実装されている、なので VB.NET で wkList.Count では拡張メソッドの Count が shadow される・・・ということのようです。

    回避策は、

    (1) Hongliang さんが書いたように明示的に拡張メソッドの Count を使用したコードにする。

    (2) 私がレスしたように ToList を止める(Count プロパティを実装してない IEnumerable(Of Int32) 型に適用する)。

    のいずれかしかなさそうです。

    2015年12月9日 5:44

すべての返信

  • 静的メソッドとして呼び出すとか。

    Enumerable.Count(wkList, Function(x) x >= 5)

    2015年12月9日 2:49
  • > ListクラスのCountプロパティとみなされてビルドエラーになります。

    MSDN ライブラリに書いてあったように "source の型が ICollection(Of T) を実装している場合は、その実装を使用して要素数を取得します。それ以外の場合は、このメソッドが数を判断します。" ということだからでは?


    【追伸】

    ToList を止めれば通るはずです。

    Dim e As IEnumerable(Of Int32) = Enumerable.Range(1, 10)
    Dim x As List(Of Int32) = e.ToList
    
    Console.WriteLine(e.Count(Function(n) n >= 5))
    
    'Public ReadOnly Property Count As Integer' には引数がないため、戻り値の型をインデックス化できません。
    'Console.WriteLine(x.Count(Function(n) n >= 5))

    C# ならどちらも OK。

     

    IEnumerable<int> e = Enumerable.Range(1, 10);
    List<int> x = e.ToList();
    
    Console.WriteLine(e.Count(n => n >= 5));
    Console.WriteLine(x.Count(n => n >= 5));

    • 編集済み SurferOnWww 2015年12月9日 3:29 追伸追加
    2015年12月9日 2:55
  • C#では全く問題ないので、不思議に思い調べてみました。

    Strange Behavior of VB 9.0 Count() Operator with Predicate  t
    https://social.msdn.microsoft.com/Forums/en-US/34a66c1f-81d4-4f6f-bab5-2a0be64db1ec/strange-behavior-of-vb-90-count-operator-with-predicate?forum=linqprojectgeneral

    Linq count?
    http://www.vbdotnetforums.com/linq/48359-linq-count.html

    上記のページでは結局解決していませんし、上記のページで紹介されているconnectのページも今は存在しないようです。
    今のところちょっと謎ですね・・・


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/


    • 編集済み trapemiyaModerator 2015年12月9日 4:31 リンク先にうまく飛ばないので再設定
    2015年12月9日 4:27
    モデレータ
  • 以下の説明によると、VBでは()を使ってプロパティにアクセスできるので(配列プロパティですね)、プロパティとメソッドとの区別ができないんだとか・・・。というわけで、言語仕様上の限界のように思えます。

    How do I specify Enumerable.Count() instead of List.Count?
    http://stackoverflow.com/questions/15961308/how-do-i-specify-enumerable-count-instead-of-list-count


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    2015年12月9日 5:38
    モデレータ
  • > 今のところちょっと謎ですね・・・

    trapemiya さんが紹介された MSDN Forum のスレッドで、Matt Warren - MSFT さんが、

    "VB compiler is matching the lists Count property instead of the Enumerable.Count() extension method and the Count property is blocking the visibility of the extension method's other signature."

    Timothy Ng MSFT さんが、

    "in VB, properties shadow methods (and thus, extension methods) by name."

    と書いた説明、即ち VB.NET のコンパイラの問題ということで自分的には納得しているのですが。(公式文書ではないといわれるかもしれませんが)

    質問者さんのコードで wkList は List(Of Int32) 型、List(Of Int32) 型には Count プロパティが実装されている、なので VB.NET で wkList.Count では拡張メソッドの Count が shadow される・・・ということのようです。

    回避策は、

    (1) Hongliang さんが書いたように明示的に拡張メソッドの Count を使用したコードにする。

    (2) 私がレスしたように ToList を止める(Count プロパティを実装してない IEnumerable(Of Int32) 型に適用する)。

    のいずれかしかなさそうです。

    2015年12月9日 5:44
  • SurferOnWwwさんの書かれている通りだと思います。ありがとうございます。

    理由は先の私が書き込んだVBの配列プロパティということで、私的にはかなりすっきりしてます。C#にはこの機能が無く([]を使う似たようなのはありますが)、問題ないということですね。


    ★良い回答には回答済みマークを付けよう! MVP - .NET  http://d.hatena.ne.jp/trapemiya/

    2015年12月9日 6:09
    モデレータ
  • VBの言語仕様ということで納得しました。
    ありがとうございました。
    2015年12月9日 6:35