4

最近、醜いコードと思われるコードをクリーンアップする方法について質問しました。推奨事項の 1 つは、必要な機能を実行し、必要なものを返す拡張メソッドを作成することでした。私の最初の考えは「素晴らしい!拡張機能ってなんてクールなの...」と思いますが、もう少し考えてみると、拡張機能の使用について考え直し始めています...

私の主な懸念は、拡張機能がカスタムの「ショートカット」であり、他の開発者が従うのを難しくしているように見えることです。拡張機能を使用するとコード構文が読みやすくなることは理解していますが、カーテンの後ろの声に従うのはどうでしょうか?

たとえば、以前の質問のコード スニペットを見てみましょう。

if (entry.Properties["something"].Value != null)
  attribs.something = entry.Properties["something"].Value.ToString();

次に、拡張機能に置き換えます。

public static class ObjectExtensions
{
    public static string NullSafeToString(this object obj)
    {
        return obj != null ? obj.ToString() : String.Empty;
    }
}

次の構文を使用して呼び出します。

attribs.something = entry.Properties["something"].Value.NullSafeToString();

確かに便利な方法ですが、別のクラスオブジェクトのオーバーヘッドに本当に価値があるのでしょうか? 誰かが私のコード スニペットを再利用したいが、拡張機能を理解していない場合はどうなりますか? 同じ結果の構文を同じように簡単に使用できたはずです。

attribs.something = (entry.Properties["something"].Value ?? string.Empty).ToString()

そこで、少し掘り下げて、拡張機能を使用することの長所と短所について話している記事をいくつか見つけました。興味のある方は、次のリンクをご覧ください。

MSDN: 拡張メソッド

拡張メソッドのベスト プラクティス

拡張方法

どちらが良い方法なのか、一概には言えません。自分のやりたいことを実行するカスタム拡張機能、または同じタスクを達成するためのより多くのコードが表示されますか? 「本物の」開発者がこのトピックについてどう思うか知りたいです...

4

5 に答える 5

20

個人的には、拡張メソッドの可読性の「問題」は非常に誇張されていると思います。コードが何を行っているかという点でコードを読みやすくすることに専念する場合、ほとんどの場合、それはどのように行うかよりも重要です。開発者が裏で実際に何が起こっているのかを追跡して調べたい場合は、いつでもクリックして実装にアクセスできます。

拡張メソッドに関する私の主な問題は、それらの検出方法です。つまり、指定されたクラスではなく、指定された名前空間を使用します。それはまた別問題ですが(笑)

任意に拡張メソッドを挿入することを提案しているわけではありませんが、メソッド内のすべての式がどのように機能するかを知る必要がある頻度と、それがより広い意味で何をするかを調べるためにざっと目を通す必要があるかを真剣に検討します。

編集: 用語の使用が少し誤解を招く可能性があります。「拡張オブジェクト」のようなものはありません。「拡張メソッド」だけがあり、それらは静的型に存在する必要があります。したがって、新しいタイプを導入する必要があるかもしれませんが、それ以上オブジェクトを作成していません。

于 2009-02-15T21:10:03.540 に答える
6

[OP] 確かに便利な方法ですが、別のクラス オブジェクトのオーバーヘッドに見合うだけの価値はありますか?

このシナリオでは、追加のクラス オブジェクトは作成されません。内部的には、拡張メソッドは静的メソッドと同じように呼び出されます。拡張メソッド コンテナー用の追加のメタデータ エントリがありますが、それはごくわずかです。

[OP] 誰かが私のコード スニペットを再利用したいが、拡張オブジェクトを理解していない場合はどうなりますか?

それなら、彼らを教育する良い機会になるでしょう:)。はい、新しい開発者が拡張メソッドを開始することに慣れていない可能性があるというリスクがあります。しかし、これは孤立した機能ではありません。これは、私が内部および Web 上で見ているすべてのコード サンプルでますます使用されています。これは、開発者が学ぶ価値のあるものです。「人に知ってもらうことを難解に」という範疇には入らないと思います

于 2009-02-15T21:09:43.197 に答える
5

拡張メソッドで対処する唯一の深刻な奇妙さは次のとおりです。

  1. 左側 (メソッドを呼び出しているように見えるオブジェクト) が null の場合、null 参照例外を発生させる必要はありません。
    • は有用な場合もありますが、期待に反するものであるため、細心の注意を払って使用する必要があります。
  2. それらが適用されるクラス/インターフェースのリフレクションを通じてアクセスすることはできません。
    • 通常は問題ありませんが、覚えておく価値があります。
  3. 他の拡張メソッドとの名前の競合には、長い解決ルール シーケンスが含まれます。
    • シーケンスが優先されることを気にする場合:
      1. 現在のモジュール内で定義されている拡張メソッド。
      2. 現在の名前空間またはその親のいずれかのデータ型内で定義された拡張メソッド。子の名前空間は親の名前空間よりも優先されます。
      3. 現在のファイルの型インポート内で定義された拡張メソッド。
      4. 現在のファイルの名前空間インポート内で定義された拡張メソッド。
      5. プロジェクト レベルの型のインポート内で定義された拡張メソッド。
      6. プロジェクト レベルの名前空間のインポート内で定義された拡張メソッド。
于 2009-02-15T21:35:19.593 に答える
2

[OP] 誰かが私のコード スニペットを再利用したいが、拡張オブジェクトを理解していない場合はどうなりますか?

拡張メソッドは、それらを実装するアセンブリがプロジェクトで参照されていない場合、オブジェクトの IntelliSense に表示されません。コード スニペットもコンパイルされません。これにより、他の開発者が少し混乱する可能性があります。

拡張メソッド アセンブリが参照されている場合は、IntelliSense で表示されますが、オブジェクトのドキュメントには記載されていません。これにより、多少の混乱が生じる可能性もあります。

ただし、@JaredPar が述べたように、技術としての拡張メソッドはますます使用されており、ほとんどの C# プログラマーがそれらについて知っていると思います。したがって、潜在的な混乱についてあまり心配する必要はありません。

于 2009-02-15T21:25:16.387 に答える
0

C# 拡張機能は、.Net が提供する追加の "ツール" で、コードをより適切に記述できるようにします。それらのもう 1 つの利点は、null を処理できることです。それらは非常に使いやすいように見えますが、コードを本当に整頓する特定のケースでのみ使用しようとしています。これらは標準のコーディング方法ではなく、静的クラスにある必要があり、他のクラスから少し離れているためです。自分自身を静的にします。

それらの実装が少し乱雑であるとしましょうが、それらの使用はより整頓されています。

それらは C# と VB.Net にしか存在しないことに注意することも重要です (Java には拡張機能がありません)。もう 1 つの重要な事実は、拡張機能は標準メソッドより優先されないということです。つまり、メソッドが同じクラスの拡張メソッドと同じ名前のクラスに実装されている場合、最初のメソッドが呼び出され、最初のメソッドは呼び出されません。延長方法。

以下に、私がそれらをよく使用する 3 つのケース、それらを使用する理由、および同じ問題を解決する代替ソリューションを示します。

1.ジェネリッククラスの特定のメソッドを実装するには: 私はジェネリック型を持っています。コレクションとしましょうList<T>。特定の種類のリストにのみ適用されるメソッドを実行したいと考えています。セパレーター ( ) を使用して文字列のリストからユニオンを作成するメソッドを考えてみましょう"A", "B", "C", " sep " --> "A sep B sep C":

public static string union(this List<string> stringList, String seperator)
{
   String unionString = "";
   foreach (string stringItem in stringList) {
      unionString += seperator + stringItem; }
   if (unionString != "") { 
      unionString = unionString.Substring(seperator.Length); }
   return unionString;
}

拡張機能を使用したくない場合は、新しいクラス " StringCollection : List<string>" を作成し、そこにメソッドを実装する必要があります。これは主に問題ではなく、ほとんどの場合は改善されますが、すべての場合ではありません。たとえば、多くの場合、すべてのデータを文字列のリストで受け取っている場合、StringCollectionsユニオンを使用するたびにそれらのリストを変換する必要はありませんが、代わりに拡張機能を使用してください。

2. null を処理する必要があるメソッドを実装するには: オブジェクトが null の場合に例外をスローせずに、オブジェクトを文字列に変換するメソッドが必要です。

public static String toStringNullAllowed(this Object inputObject)
{
   if (inputObject == null) { return null; }
   return inputObject.ToString();
}

拡張機能を使用したくない場合は、クラス (おそらく静的) を作成する必要がStringConverterあります。myObject.toStringNullAllowed();

3. 値型またはシール クラスを拡張するには: int、float、string などの値型およびシール クラス (継承できないクラス) は継承によって拡張できません。以下に、x 桁の文字列に変換できるように整数を拡張する例を示します (例integer 34, digits 5 --> "00034": )。

public static String toXDigit(this int inputInteger, int x)
{
   String xDigitNumber = inputInteger.ToString();
   while (xDigitNumber.Length < x) { xDigitNumber = "0" + xDigitNumber; }
   return xDigitNumber;
}

繰り返しますが、別の解決策は静的クラス (ツールボックスなど) です。「数学」としましょう。

  • その場合、次のように記述します。Math.toXDigit(a, x);
  • 拡張メソッドを使用している間:a.toXDigit(x);

拡張メソッドは見栄えが良く、英語を話すように理解しやすくなっています

結論として、拡張機能の欠点は、その実装が標準クラスから分離されており、慣れていないプログラマーにとっては少し奇妙または難しいように見えることですが、拡張機能の利点は、より理解しやすく、整理され、カプセル化された使用法を提供することです。言語の。

于 2014-01-16T12:50:02.273 に答える