メソッドを変更して、指定されたプロパティの値を返すために内部オブジェクトで使用されるラムダ式を取得する追加のパラメーターを持つようにする必要があります。これはLINQ式への私の最初の進出なので、用語の誤った使用の可能性を許してください!
回答を検索してみましたが、前述のように、用語が間違っているようで、見つけることができる例が複雑すぎたり、慣れている.Where()
などのコレクション関数の式を扱ったりしています。と。
私がこれまでに持っているもの(カットダウンバージョン):
class MyClass
{
private MyObject _myObject = new MyObject() { Name = "Test", Code = "T" };
private string MyMethod(int testParameter, ??? selector)
{
//return _myObject.Name;
//return _myObject.Code;
return ???;
}
}
私はそれを次のようなものにしたいと思います:
string result = _myClassInstance.MyMethod(1, (x => x.Name));
または:
string result = _myClassInstance.MyMethod(1, (x => x.Code));
明らかに、欠けている部分はselector
のMyMethod
パラメータです。ローカル変数に適用する方法と、必要なプロパティを呼び出すときにメソッドに渡す方法です。
VB.NETソリューションの追加のボーナスポイント、そして残念ながら最終的な実装は、私たちの唯一のVBプロジェクトに含まれている必要があります。
private string MyMethod(int testParameter, Func<MyObject, string> selector)
{
return selector(_myObject);
}
Func
デリゲートを使用する場合、最後のパラメーターは戻り値の型であり、最初のN-1は引数の型です。この場合、MyObject
への単一のselector
引数があり、string
を返します。
あなたはそれを次のように呼び出すことができます:
string name = _myClassInstance.MyMethod(1, x => x.Name);
string result = _myClassInstance.MyMethod(1, x => x.Code);
MyMethod
の戻り値の型はselector
デリゲートの戻り値の型と一致するため、ジェネリックにすることができます。
private T MyMethod<T>(int testParameter, Func<MyObject, T> selector)
{
MyObject obj = //
return selector(obj);
}
編集:VB.Netはわかりませんが、次のようになります:
Public Function MyMethod(testParameter as Integer, selector as Func(Of MyObject, String))
Return selector(_myObject)
End Function
そして一般的なバージョンは次のようになります:
Public Function MyMethod(Of T)(testParameter as Integer, selector Func(Of MyObject, T))
Return selector(_myObject)
End Function
非常に柔軟な別のアプローチを紹介します(下部のDotNetFiddleを参照):あなたは簡単に独自の [〜#〜] linq [〜#〜] functionsを使用して、既存の関数を拡張するか、独自の関数を記述して、LINQクエリの機能を活用します。
この例では、グループ化に使用するフィールドを指定できるように、LinqのDistinct
関数を改善しています。
使用方法(例):
_var myQuery=(from x in Customers select x).MyDistinct(d => d.CustomerID);
_
この例では、クエリはCustomerID
でグループ化されており、各グループの最初の要素が返されます。
MyDistinct
:の宣言
_public static class Extensions
{
public static IEnumerable<T> MyDistinct<T, V>(this IEnumerable<T> query,
Func<T, V> f)
{
return query.GroupBy(f).Select(x=>x.First());
}
}
_
2番目のパラメーターであるf
は_Func<T, V>
_として宣言されているので、_.GroupBy
_ステートメントで使用できます。
宣言している場合は、質問のコードに戻ります
_class MyObject
{
public string Name;
public string Code;
}
private MyObject[] _myObject = {
new MyObject() { Name = "Test1", Code = "T"},
new MyObject() { Name = "Test2", Code = "Q"},
new MyObject() { Name = "Test2", Code = "T"},
new MyObject() { Name = "Test5", Code = "Q"}
};
_
次のように、新しく定義した関数MyDistinct
でそれを使用できます。
_var myQuery = (from x in _myObject select x).MyDistinct(d => d.Code);
_
戻ります
名前コード
Test1 T
テスト2 Q
または、クエリで.MyDistinct(d => d.Name)
を使用できます。
名前コード
Test1 T
テスト2 Q
テスト5 Q
MyDistinct
はジェネリックT
およびV
で宣言されているため、正しいオブジェクトタイプを自動的に認識して使用し、MyObject
要素を返します。
高度な使用法
MyDistinct
は常に各グループの最初の要素を取ることに注意してください。必要な要素を定義する条件が必要な場合はどうなりますか?
方法は次のとおりです。
_public static class Extensions
{
public static IEnumerable<T> MyDistinct<T, V>(this IEnumerable<T> query,
Func<T, V> f,
Func<IGrouping<V,T>,T> h=null)
{
if (h==null) h=(x => x.First());
return query.GroupBy(f).Select(h);
}
}
_
この変更により、以前と同じように使用できます。つまり、.MyDistinct(d => d.Name)
のような1つのパラメーターを指定しますが、x => x.FirstOrDefault(y => y.Name.Contains("1")||y.Name.Contains("2"))
などの条件を2番目のパラメーターとして指定することもできます。そう:
_var myQuery2 = (from x in _myObject select x).MyDistinct(d => d.Name,
x=>x.FirstOrDefault(y=>y.Name.Contains("1")||y.Name.Contains("2"))
);
_
このクエリを実行すると、結果は次のようになります。
名前コード
Test1 T
テスト2 Q
ヌル
_Test5
_は条件を満たさない(1または2を含まない)ため、3行目にnullが返されます。
注:条件のみを公開したい場合は、次のように実装することでさらに簡単にすることができます。
_public static IEnumerable<T> MyDistinct2<T, V>(this IEnumerable<T> query,
Func<T, V> f,
Func<T,bool> h=null
)
{
if (h == null) h = (y => true);
return query.GroupBy(f).Select(x=>x.FirstOrDefault(h));
}
_
この場合、クエリは次のようになります。
_var myQuery3 = (from x in _myObject select x).MyDistinct2(d => d.Name,
y => y.Name.Contains("1") || y.Name.Contains("2")
);
_
したがって、x=>x.FirstOrDefault(... condition ...)
を記述する必要はありません。
c#で
Funcが探しているパラメータタイプ
private string MyMethod(int testParameter, Func<MyClass,string> selector){
return selector(_myObject);
}
VBでも、Funcが必要です。構文は少し異なります。
Function MyMethod(ByVal testParameter As Integer, ByVal selector as Func(Of MyClass,string) as string
return selector(_myObject)
End Function
class MyClass
{
private MyObject _myObject = new MyObject() { Name = "Test", Code = "T" };
private string MyMethod(int testParameter, Func<MyObject, string> selector)
{
return selector(_myObject );
}
}
セレクターのデリゲートでそれを行うことができます:
delegate string SampleDelegate(MyObject obj);
private string MyMethod(int testParameter, SampleDelegate selector)
{
return selector(_myObject);
}
Delegateクラス(VBでは「Delegate」、C#では「delegate」)、またはそのサブタイプの1つを探している可能性があります。
このページ には、特にページの下部付近に役立つと思われる例がいくつかあります。
ここにVBしたいことの例があります:
Public Class MyClass
Private Property _myObject As MyObject = New MyObject With {.Name = "Test", .Code = "T"}
Private Function MyMethod(testParameter As Integer, selector As Func(Of MyObject, String)) As String
Return selector(_myObject).ToString
End Function
End Class