2016-08-17 6 views
0

Scott Hanselman's blogに基づいてVBでToCSV()拡張を書き込もうとしています。それは私のC#のVBには正しくないことがありますが、それはすべて正しいようです。パブリックメンバ 'ToCSVValue'タイプの 'Integer'がVB拡張メソッドで見つかりません

Dim s As String = ctx.Customers.Where(Function(x) x.CustomerID = 123456).Select(Function(x) New With {.CustomerID = x.CustomerID, .CustomerName = x.CustomerName}).ToCSV() 

それがうまく機能ToCSVに取得します。私のようなもので、それを呼び出す

<System.Runtime.CompilerServices.Extension> 
Public Function ToCSV(Of T)(items As IEnumerable(Of T)) As String 
    Try 

     Dim csvBuilder = New StringBuilder() 
     Dim properties = GetType(T).GetProperties() 

     For Each item As T In items 

      '' Test Code 
      Dim newline As String = "" 
      For Each l2 As Reflection.PropertyInfo In properties 

       ' This works 
       newline &= l2.GetValue(item, Nothing) 

       ' This works too 
       Dim int As Integer = 1234 
       Dim s As String = int.ToCSVValue() 

       'This works 
       Dim nl = l2.GetValue(item, Nothing) 

       ' This blows up with "Public member 'ToCSVValue' on type 'Integer' not found." 
       ' The Debugger type shows "Object {Integer}" which I assume to mean that the debugger interprets the object as an integer. 
       nl = nl.ToCSVValue() 
      Next 

      ' Original code 
      Dim line As String = String.Join(",", properties.Select(Function(p) p.GetValue(item, Nothing).ToCSVValue()).ToArray()) 
      csvBuilder.AppendLine(line) 
     Next 

     Return csvBuilder.ToString() 

    Catch ex As Exception 
     Throw 
    End Try 

End Function 


<System.Runtime.CompilerServices.Extension> 
Private Function ToCSVValue(Of T)(item As T) As String 

    If item Is Nothing Then 
     Return """""" 
    End If 

    If TypeOf item Is String Then 
     Return String.Format("""{0}""", item.ToString().Replace("""", "\""")) 
    End If 
    Dim dummy As Double 
    If Double.TryParse(item.ToString(), dummy) Then 
     Return String.Format("{0}", item) 
    End If 
    Return String.Format("""{0}""", item) 

End Function 

: は、私はモジュールを追加しました。それは渡された項目を認識します。最初の項目を引き出し、その中に2つの項目があることがわかります。すべていいよ!

GetValue()はうまく動作します。

静的な整数を作成し、ToCSVValueを呼び出すと正常に動作します。 静的な文字列を作成し、ToCSVValueを呼び出すと正常に動作します。

GetValue()でToCSVValueを呼び出すと、次のようになります。 パブリックメンバ 'ToCSVValue'が 'Integer'型で見つかりません。

同様に、データセットに文字列がある場合は、 タイプ 'String'のパブリックメンバー 'ToCSVValue'が見つかりません。

理想的には、これは「オリジナルコード」のセクションと同じように機能し、この他のすべてのテストコードを強制終了できます。

何が起こっているのか、「(Of T)」がGet GetValue()型を処理していない理由を教えてもらえますか?

+0

をうーん...わからないがなぜなら、あなたが 'ToCSVValue(nl)'を使用すると動作します – Slai

+0

あなたは正しいです。このように動作します。しかし、どうやって意図どおりに動作させることができますか? 'foo.ToCSV()' –

答えて

0

「Option Infer On」が必要です。 Option Infer Onを使用すると問題なく動作します。

これを使用しないと、VBはタイプを終了するたびに「オブジェクト」を使用しています。これはあなたの問題を引き起こしていないが

はまた、ToCSV方法の適切な変換は、次のとおりです。

Public Function ToCSV(Of T As Class)(items As IEnumerable(Of T)) As String 
+0

これは良いショットでしたが、同じエラーです。以前はプロジェクトでも使用されていました。私はそれを明示的にチェックするだけで追加し、同じエラーが発生しました。 –

+0

「As Class」を追加すると、関数に制約が追加されることがわかります。私はなぜそれが必要か、示唆されているか分からない。説明してくれませんか? –

+0

@JustinTolchin:これは、これが参照型と値の型にのみ適用可能であると著者が判断したためです。 –

0

短い答えは方法ToCSVValue(p.GetValue(item, Nothing))としてそれを呼び出すと、C#バージョンのように動作することです。

もっと長い答えは、VBのObjectで拡張メソッドを呼び出すことができないということです。 VBではObjectはC#でdynamicのように扱われます。たとえば:

<Extension()> Function toStr(Of T)(item As T) As String 
    Return item.ToString 
End Function 

が、これは「Late bound resolution; runtime errors could occur.」を警告し、実行時エラー「Public member 'toStr' on type 'Integer' not found.」コンパイル時になりますが、それはC#で動作します:

Dim i As Object = 123 
Dim s = i.toStr 
関連する問題