web-dev-qa-db-ja.com

汎用拡張メソッドを作成する方法は?

私は、文字列をアルファベット順に、次に縦方向に昇順に並べる汎用拡張メソッドを開発したいと思います。

というのは

string[] names = { "Jon", "Marc", "Joel",
                  "Thomas", "Copsey","Konrad","Andrew","Brian","Bill"};

var query = names.OrderBy(a => a.Length).ThenBy(a => a);

Generic Extension Methodを開発する方法は何ですか?

私は試した :

public static class ExtensionOperation
    {
        public static T[] AlphaLengthWise<T>(this T[] names)
        {
            var query = names.OrderBy(a => a.Length).ThenBy(a => a);
            return query;
        }
    }

私は受け取った:

エラー1:Tには長さの定義が含まれていません

エラー2:変換できませんSystem.Linq.IOrderedEnumerableからT[]

63
user215675

最初のエラーは、LengthStringクラスのプロパティである一方、ジェネリックバージョンではTパラメーターのタイプが不明であるためです。どのタイプでもかまいません。

2番目のエラーは、実際の結果ではなくクエリオブジェクトのみを返すためです。戻る前にToArray()を呼び出す必要があるかもしれません。

少し修正するだけで、次のことが可能になります。

public static class ExtensionOperation
{
    public static IEnumerable<T> AlphaLengthWise<T, L>(
        this IEnumerable<T> names, Func<T, L> lengthProvider)
    {
        return names
            .OrderBy(a => lengthProvider(a))
            .ThenBy(a => a);
    }
}

次のように使用できます:

string[] names = { "Jon", "Marc", "Joel", "Thomas", "Copsey", "Konrad", "Andrew", "Brian", "Bill" };
var result = names.AlphaLengthWise(a => a.Length);
94
Darin Dimitrov

なぜこれを一般的にしたいのですか?使うだけ

public static class ExtensionOperations
{
    public static IEnumerable<string> AlphaLengthWise(this string[] names)
    {
        var query = names.OrderBy(a => a.Length).ThenBy(a => a);
        return query;
    }
}
14

ジェネリックの目的について少し混乱していると思います。

ジェネリックは、クラスまたはメソッドを特定の型に合わせて調整する方法です。ジェネリックメソッドまたはクラスは、anyタイプで機能するように設計されています。これはList<T>クラスで最も簡単に説明されており、任意のタイプのリストに合わせて調整できます。これにより、リストにその特定のタイプのみが含まれることを知るタイプセーフティが得られます。

問題は、特定のタイプ、stringタイプで機能するように設計されています。ジェネリックは、特定のタイプに関係する問題を解決しません。

必要なのは、単純な(非汎用)拡張メソッドです。

public static class ExtensionOperations
{
    public static IEnumerable<string> AlphaLengthWise(
        this IEnumerable<string> names)
    {
        if(names == null)
            throw new ArgumentNullException("names");

        return names.OrderBy(a => a.Length).ThenBy(a => a);
    }
}

引数と戻り値の型をIEnumerable<string>にすると、これはIEnumerable<string>を実装する任意の型に適用できる非汎用の拡張メソッドになります。これには、string[]List<string>ICollection<string>IQueryable<string>などが含まれます。

7
Paul Turner

なぜ一般的なものにしたいのですか?

これは、TにLengthプロパティがある場合にのみ機能し、それを強制するにはインターフェイスが必要です。

さらに、TはIComparableでなければなりません。

4
Henk Holterman

文字列をアルファベット順に配置する汎用拡張メソッドを開発したい...

public static class ExtensionOperation
{
    public static IEnumerable<String> AplhaLengthWise(
                                   this IEnumerable<String> names)
    {
        return names.OrderBy(a => a.Length).ThenBy(a => a);
    }
}
2
Alex Bagnolini

マイクロソフトが行う方法をコピーします。

public static class ExtensionOperation {
    // Handles anything queryable.
    public static IOrderedQueryable<string> AlphaLengthWise(this IQueryable<string> names) {
        return names.OrderBy(a => a.Length).ThenBy(a => a);
    }
    // Fallback method for non-queryable collections.
    public static IOrderedEnumerable<string> AlphaLengthWise(this IEnumerable<string> names) {
        return names.OrderBy(a => a.Length).ThenBy(a => a);
    }
}
1

_IEnumerable<T>_の代わりに_T[]_を使用します。それ以外は、LengthTを使用することはできません。すべてのタイプにLengthプロパティがあるわけではないためです。拡張メソッドを.OrderBy(a => a.ToString().Length)に変更できます

常に文字列を処理することがわかっている場合は、_IEnumerable<String>_ではなく_IEnumerable<T>_を使用すると、Lengthプロパティにすぐにアクセスできます。

0
David Hedlund