7

拡張メソッドを呼び出しているインスタンスを返す拡張メソッドを作成することは可能ですか?

ICollection<T>から継承し、オブジェクトを返すものすべての拡張メソッドが欲しいのですが。jQueryが常にjqueryオブジェクトを返す方法とよく似ています。

public static object AddItem<T>(this ICollection<T> collection, T itemToAdd)
{
    collection.Add(itemToAdd);
    return collection;
{

上記のようなものを想像しますが、次のようなものを使用するために「this」オブジェクトタイプの親に戻る方法がわかりません。

List<int> myInts = new List<int>().AddItem(5);

編集:私が単一の一般的な制約ソリューションを望んでいたことを明確にしたかっただけです。

4

5 に答える 5

13

特定のタイプを返す必要がある場合は、一般的な制約を使用できます。

public static TCollection AddItem<TCollection, TElement>(
    this TCollection collection,
    TElement itemToAdd)
    where TCollection : ICollection<TElement>
{
    collection.Add(itemToAdd);
    return collection;
}

これをテストしたところ、VS2010で動作します。

更新(jQueryに関して):

JavaScriptは動的型付けを使用するため、jQueryチェーンは非常にうまく機能します。C#4.0はをサポートしているdynamicため、次のことができます。

public static dynamic AddItem<T>(this ICollection<T> collection, T itemToAdd)
{
    collection.Add(itemToAdd);
    return collection;
}

ただし、一般的な制約バージョンをお勧めします。これは、タイプセーフで効率的であり、返されたタイプでIntelliSenseを使用できるためです。より複雑なシナリオでは、ジェネリック制約が常に必要なものを表現できるとは限りません。そのような場合は、dynamic使用できます(ただし、追加の拡張メソッドにバインドされないため、チェーンではうまく機能しません)。

于 2010-07-09T19:58:51.380 に答える
4

私はこれを試すためにVSを開いていませんが、これらの線に沿った何かが機能するはずです:

public static TCollection AddItem<TCollection, TItem>(TCollection collection, 
                                                      TItem itemToAdd) 
where TCollection : ICollection<TItem>
{
    collection.Add(itemToAdd);
    return collection;
}
于 2010-07-09T19:59:04.640 に答える
2

あなたは2つの相反する目標を持っているようです、そしてそれはあなたがあなたの拡張メソッドに何を返したいかということになります:

  • 拡張メソッドを呼び出したインスタンス(コレクション)
  • またはコレクションに追加されたアイテム

使用例から、ここに引用:

List<int> myInts = new List<int>().AddItem(5);

コレクションを返却したいように見せます。いずれにせよ、拡張メソッドは次のようにICollectionの戻り型を持っている必要があるため、その割り当てはキャストなしでは機能しません。

public static ICollection<T> AddItem<T>(this ICollection<T> collection, T itemToAdd)
{
    collection.Add(itemToAdd);
    return collection;
}

それはあなたがこれをすることを可能にするでしょう:

List<int> myList = (List<int>) new List<int>().AddItem(5);

これで、追加されたオブジェクトを返す場合でも、returnタイプを。にする必要はありませんobject。ジェネリック型パラメーターを利用してT、次のように返す必要があります。

public static T AddItem<T>(this ICollection<T> collection, T itemToAdd)
{
    collection.Add(itemToAdd);
    return itemToAdd;
}

ただし、追加されたアイテムを返品する場合は、次のようにチェーンすることはできません。

List<int> myList = (List<int>) new List<int>().AddItem(5);

、の戻り型はICollectionでAddItem(5)ないためTですが、 (intこの場合は)です。ただし、次のように、付加価値から離れてチェーンすることはできます。

List<int> myList = new List<int>();
myList.AddItem(5).DoSomethingWithMyInt(); // Not very useful in this case

最初の割り当てステートメントからすぐにチェーンできるため、最初のシナリオ(コレクションを返す)の方が便利なようです。その大きな例を次に示します。

List<int> myList = (List<int>) new List<int>().AddItem(1).AddItem(2);

または、キャストしたくない場合は、ToList()戻ってきたICollectionを呼び出すことができます。

List<int> myList = new List<int>().AddItem(1).AddItem(2).ToList();
于 2010-07-09T20:09:17.893 に答える
1

編集:私が単一の一般的な制約ソリューションを望んでいたことを明確にしたかっただけです。

この場合、リターン型の変換は共変である可能性がありますが、反変ではないため(つまり、からICollection<T>を暗黙的に変換することはできませんList<T>)、ジェネリックのリターン型がないとこれを行うことができないため、運が悪いです。

とにかく2つのタイプパラメータを指定することの何が問題になっていますか?それらは、関数に提供する引数によって推測できるため、呼び出し元のコードで実際に気付くことさえありません。

于 2010-07-09T20:13:58.317 に答える
0

ICollection<T>代わりに戻るだけでobject、すべてが意図したとおりに機能するはずです。

于 2010-07-09T20:00:00.660 に答える