2017-02-13 6 views
-1

私はgeneric methodは、次のコードからArrayを拡張するために取得しようとしています:ジェネリック機能(downvoted)

Public Class clsField 
    Public idx As String 
    Public name As String 
    Public weight As Long 

    Public Sub New(i As String, n As String, w As Long) 
     idx = i : name = n : weight = w 
    End Sub 
End Class 

Public Class Container 
    Public fields As clsField() ' filled in by a JSON parser (order matters) 

    ' returns a list sorted by clsField.weight preserving order for elements with same 'weight' value 
    Public Function getFields() As List(Of KeyValuePair(Of String, clsField)) 
     Dim auxList As List(Of KeyValuePair(Of String, clsField)) 

     If (fields Is Nothing) OrElse (fields.Count < 1) Then Return New List(Of KeyValuePair(Of String, clsField)) 
     ' .ToList to transform IEnumerable to the return type 
     auxList = Array.ConvertAll(fields, New Converter(Of clsField, KeyValuePair(Of String, clsField))(AddressOf FieldToPair)).ToList 
     Return auxList.OrderBy(Function(x) x.Value.weight).ToList() 
    End Function 

    Public Shared Function FieldToPair(fld As clsField) As KeyValuePair(Of String, clsField) 
     Return New KeyValuePair(Of String, clsField)(fld.idx, fld) 
    End Function 
End Class 

私はArray.ConvertAllで使用Converter(Of TInput, TOutput) Delegate、で立ち往生しています、新しいパラメータを受け入れないであろう、私はTInputで使用する必要がありkeyを指定する関数を渡すことができ提供:

Private Function ClassToPair(Of T)(obj As T, getProperty As Func(Of T, Object)) As KeyValuePair(Of String, T) 
    Return New KeyValuePair(Of String, T)(getProperty(obj), obj) 
End Function 

おそらくへの道がありますOverloadArray.ConvertAllを入力し、次のコードを完成させるシグニチャ(ConvertAllAddressOf ClassToPairについては明らかにコンパイルしないでください)を使用して代替DelegateConverterを作成してください。 )アイデアを反映するためにここに追加:だから

Module ArrayExtension ' custom method for array 
    ' returns a list sorted by clsField.weight preserving order for elements with same 'weight' value 
    ' getKey is used to transform the array into a List (Of KeyValuePair (Of String, T)) -> using the Converter 
    ' getSortProperty is used to change the sorting 'property' 
    <Extension()> 
    Public Function toSortedPairedList(Of T)(arr As T(), Optional getKey As Func(Of T, String) = Nothing, 
      Optional getSortProperty As Func(Of KeyValuePair(Of String, T), Object) = Nothing) _ 
      As List(Of KeyValuePair(Of String, T)) 
     Dim auxList As List(Of KeyValuePair(Of String, T)) 

     If (arr Is Nothing) OrElse (arr.Count < 1) Then Return New List(Of KeyValuePair(Of String, T)) 

     ' .ToList to transform IEnumerable to the return type 
     auxList = Array.ConvertAll(arr, New Converter(Of T, KeyValuePair(Of String, T))(AddressOf ClassToPair)).ToList 
     Return auxList.OrderBy(getSortProperty).ToList() 

    End Function 

    Private Function ClassToPair(Of T)(obj As T, getProperty As Func(Of T, Object)) As KeyValuePair(Of String, T) 
     Return New KeyValuePair(Of String, T)(getProperty(obj), obj) 
    End Function 
End Module 

コンバータgetKey機能を渡す方法はありません...

を最初に例えばその使用量はのようになります。

Public Function getFields() As List(Of KeyValuePair(Of String, clsField)) 
    Dim auxList As List(Of KeyValuePair(Of String, clsField)) 

    If (fields Is Nothing) OrElse (fields.Count < 1) Then Return New List(Of KeyValuePair(Of String, clsField)) 

    Return fields.toSortedPairedList(Function(x) x.idx, Function(y) y.Value.weight) 
End Function 
+0

これは、含まれているオブジェクト 'T' [...' array()としてT']のプロパティにアクセスする 'Func'' getProperty'を**保存せずに行うことはできません。変換中に 'KeyValuePair'を生成するために' TKey'を使用します。したがって、変換を実装する関数は、 'getProperty'を最初に**アクセス可能な**変数に格納し、' ClassToPair'から呼び出します。つまり、これは2回実装する必要があります:** 1。**ストア 'getProperty'、** 2。**' Array.ConvertAll' ... – rellampec

答えて

0

私は私の質問に対する答えを提供します。

クリーンな理由(メソッドの型パラメータが多すぎる)ではこのアプローチが嫌いですが、Extension Methodsを使用して解決する唯一のアプローチと思われます。

それは、Converterの使用を可能にする一般的な、モジュール変数にKeySelectorを記憶することによって、Delegate署名が導入されて制限を回避作業の利点を有する:Private accessKey As Object

私の推測によれば、最良のアプローチは、KeyValuePairsにのみ依存するのではなく、より多くのコンバージョンを持つ完全な汎用クラスの実装です。私たちはコンパイルエラー(reference)とgeneric lambdaを保存することができますので

まず第一に、へList(Of TValue)List(Of KeyValuePair(Of TKey, TValue))ConvertAllに役立つKeySelectorを格納することを目的に、一般的なクラスが必要である(あるようです)Converter Delegate紹介という制限を回避するためにもっと良い方法がない:

' to store a generic lambda: https://stackoverflow.com/a/3116009/6215377 
' the class shows up to be necessary, as it cannot be stored by the use of generic delegates 
' otherwise, you will always end up having to instantiate to specific types for KeyValuePair, 
' losing so the generic declaration 
Interface IAccesser(Of TValue, TKey) 
    Function accessProperty(input As TValue) As TKey 
End Interface 

Public Class PropertyAccessor(Of TValue, TKey) 
    Implements IAccesser(Of TValue, TKey) 
    Private pFunc As Func(Of TValue, TKey) 

    Public Sub New(f As Func(Of TValue, TKey)) 
     pFunc = f 
    End Sub 
    Function accessProperty(o As TValue) As TKey Implements IAccesser(Of TValue, TKey).accessProperty 
     Return pFunc(o) 
    End Function 
End Class 

Extension Module再適応し、toSortedPairedListに引数として渡さgetKey機能がに格納されていることを提供モジュールaccessKey As ObjectのオブジェクトをConvertAllと呼び、ClassToPairConverteraccessKeyを使用するもの)と呼びます。これはObjectからクラスPropertyAccessorにいくつかのtype castings必要になります。

Imports System.Linq.Enumerable 
Imports System.Runtime.CompilerServices ' for extensions 

Module ArrayExtension ' custom method for array 
    Private accessKey As Object ' to store the generic lambda 

    Private Function ClassToPair(Of TValue, TKey)(obj As TValue) As KeyValuePair(Of TKey, TValue) ' the Converter 
     ' this is the one that avoids to mess around with delegates (as instances of delegates cannot be generic) 
     Dim a As PropertyAccessor(Of TValue, TKey) = DirectCast(accessKey, PropertyAccessor(Of TValue, TKey)) 
     Return New KeyValuePair(Of TKey, TValue)(a.accessProperty(obj), obj) 
    End Function 

    <Extension()> ' the type params list gets long, as we target it to be generic 
    Public Function toSortedPairedList(Of TValue, TKey, TSort, TReturn)(arr As TValue(), getKey As Func(Of TValue, TKey), 
      Optional getSortProperty As Func(Of KeyValuePair(Of TKey, TValue), TSort) = Nothing) _ 
      As List(Of KeyValuePair(Of TKey, TValue)) 

     If (getKey Is Nothing) OrElse (arr Is Nothing) OrElse (arr.Count < 1) Then Return New List(Of KeyValuePair(Of TKey, TValue)) ' empty list (instead of nothing) 
     Dim a As PropertyAccessor(Of TValue, TKey) = New PropertyAccessor(Of TValue, TKey)(getKey) 
     accessKey = a ' here we store/assign, so we can use it within the Converter function ClassToPair (with the delegate signature that introduced the problem) 

     ' Typecasting Generic parameter: https://stackoverflow.com/q/2891797/6215377 (can throw an exception; i.e. TSort = Integer, TKey = non-numeric String) 
     ' NOTE: this part is not essential (just an improvement) 
     ' NOTE II: we leave the Exception Catch to the caller (an improvement would be to throw an adapted Exception from here) 
     If getSortProperty Is Nothing Then getSortProperty = Function(x) CType(CObj(a.accessProperty(x.Value)), TSort) ' defaulting to sort by getKey(obj) 

     Dim auxList As List(Of KeyValuePair(Of TKey, TValue)) 
     auxList = Array.ConvertAll(arr, New Converter(Of TValue, KeyValuePair(Of TKey, TValue))(AddressOf ClassToPair(Of TValue, TKey))).ToList() 
     Return auxList.OrderBy(getSortProperty).ToList() ' .ToList to transform IEnumerable to the return type 
    End Function 

    ' Array Extension: - https://stackoverflow.com/a/30151099/4352306 
    ' irrelevant to this question (to Push into array) 
    <Extension()> 
    Public Sub Add(Of T)(ByRef arr As T(), item As T) 
     If arr IsNot Nothing Then 
      Array.Resize(arr, arr.Length + 1) 
      arr(arr.Length - 1) = item 
     Else 
      ReDim arr(0) 
      arr(0) = item 
     End If 
    End Sub 
End Module 

をそして、最後に、これは、その使用方法を示すためテスター、次のとおりです。

Public Class clsField 
    Public idx As String 
    Public name As String 
    Public weight As Long 

    Public Sub New(i As String, n As String, w As Long) 
     idx = i : name = n : weight = w 
    End Sub 

    Public Overrides Function ToString() As String 
     Return String.Format("{0}: {1} - {2}", name, idx, weight) 
    End Function 
End Class 

Public Class Container 
    Public fields() As clsField 

    ' here we call the extended method 
    Public Function getSortedPairs() As List(Of KeyValuePair(Of String, clsField)) 
     Return fields.toSortedPairedList(Of String, Long, List(Of KeyValuePair(Of String, clsField)))(Function(f) f.idx, Function(f) f.Value.weight) 
    End Function 

    ' it calls to the function above and converts back to List(Of clsField) 
    ' NOTE: not necessary; added to show more ideas of its usability 
    Public Function getSortedFields() As List(Of clsField) 
     Return getSortedPairs.ConvertAll(Function(pair) pair.Value) 
    End Function 
End Class 

Public Class Consumer 
    Public cont As Container 

    Public Sub New() 
     cont = New Container 
     cont.fields.Add(New clsField("ffq", "foo30004", 33)) 
     cont.fields.Add(New clsField("ffc", "foo9997", 55)) 
     cont.fields.Add(New clsField("ffp", "foo9908", 55)) 
     cont.fields.Add(New clsField("ffo", "foo100001", 22)) 
     cont.fields.Add(New clsField("ffx", "foo8885", 33)) 
     cont.fields.Add(New clsField("ffz", "foo70002", 22)) 
     cont.fields.Add(New clsField("ffy", "foo8806", 33)) 
     cont.fields.Add(New clsField("ffa", "foo9009", 55)) 
     cont.fields.Add(New clsField("ffb", "foo8000", 55)) 
     cont.fields.Add(New clsField("ffn", "foo7003", 22)) 
    End Sub 

    Public Sub printSortedFields() 
     For Each e As clsField In cont.getSortedFields() 
      Console.WriteLine(e.ToString()) 
      Debug.Print(e.ToString()) 
     Next 
    End Sub 

    Public Sub Main() 
     printSortedFields() 
    End Sub 
End Class 

テストはこの出力を書き込み (名前の最後の桁がテストを確定するように作成されたエントリ):

foo100001: ffo - 22 
foo70002: ffz - 22 
foo7003: ffn - 22 
foo30004: ffq - 33 
foo8885: ffx - 33 
foo8806: ffy - 33 
foo9997: ffc - 55 
foo9908: ffp - 55 
foo9009: ffa - 55 
foo8000: ffb - 55 

似たような問題を抱えている人に役立ちます。これを決定的な解決策とは見なしませんが、generic methods and lambdasを使用してarrayslistsを並べ替えると、型変換の困難を克服する方法を取ったり破棄する方法があります。

ベスト願い

:それは同じ値を持つ要素の元の挿入順序を保持するよう順序付け方法を設計しました。

関連する問題