9

.NET の拡張メソッドの興味深い点の 1 つは、それらをインターフェイスに適用できることです。私にとっては、アセンブリを乱雑にする抽象クラスを定義することなく、インターフェイスの近くで機能を定義できることは素晴らしいことです。

抽象クラスが時代遅れなどではないことは知っていますが、コードでこの副作用を利用することについてどう思いますか?

例:

public static class IUserExtensions
{
    public static bool IsCurrentUser(this IUser user)
    {
        return (HttpContext.Current.User != null &&
                HttpContext.Current.User.Identity.Name == user.ID.ToString());
    }
}

public interface IUser {
    int ID { get; set; }
}
4

11 に答える 11

9

拡張メソッドでできることは、抽象クラスが実際に何をすべきかに焦点を当てることです。論理継承ツリーの一部ではない場合でも、実装者によって使用されるため、抽象クラスに「ユーティリティ」コードを実装したいという誘惑があります。拡張メソッドを使用すると、抽象基本クラスを乱雑にすることなく、これらのユーティリティメソッドをインターフェイスにアタッチできます。

編集

具体的には、これらのガイドラインを適用します。

継承

  • 動作が基本クラスの論理動作の一部である場合は、継承を使用してください
  • 動作が分野横断的である場合は、継承を使用しないでください(オブジェクト階層外のものに適用されます)。これらは複製が必要になります。

ユーティリティクラス

  • 動作が動作しているクラスに論理的に属していない場合は、ユーティリティクラス(静的クラス)を使用してください
  • 作用しているオブジェクトの内部状態を変更するユーティリティクラスは使用しないでください。状態の変更は、オブジェクト実装階層に対してのみ予約する必要があります。

拡張メソッド

  • 拡張メソッドの摩擦が少ない場合は、ユーティリティクラスの場合と同じ決定を使用してください。拡張メソッドを採用するのが自然ではないと感じる場合は、それを行わないでください。
  • 拡張メソッドを使用して、制御できないクラス(文字列など)にユーティリティを追加してください。
  • 動作が拡張しているクラスによって消費される場合は、拡張メソッドを使用しないでください。それは可能ですが、不自然に感じます
  • できるという理由だけで拡張メソッドを使用しないでください。実際、必要がない限り、古き良きOOPから逸脱しないでください。ただし、必要な場合、拡張メソッドは比較的有用で無害な決定を下す必要があります。

編集2

拡張メソッドの別のDOについて考えました

拡張メソッドを使用して、特定の実装に自然言語(内部DSL)を提供してください。これはばかげた例です。

int age = getAge();
if (age.IsDraftAge() && !age.IsLegalDrinkingAge())
{
    Console.WriteLine(@"You cannot drink until your birthdate on {0}.
Join the army instead.",
                      age.GetYearWhenGettingDrunkIsOk());
}
于 2009-03-16T20:03:39.320 に答える
4

私はこの機能を数回使用しました。実際、この機能はインターフェイスを変更せずに装飾する目的で特別に作成されたため、LINQ. (少なくともオブジェクトに対する) LINQ の利点はすべて、IEnumerable<T> の拡張メソッドに基づいています。

ただし、拡張メソッドが必要なときに抽象基本クラスを置き換えるとはまったく思いません。拡張メソッドは、拡張されたクラスのプライベート状態にアクセスできません。拡張メソッドはインスタンスのように見えますが、依然として静的です。

拡張メソッドと抽象基本クラスは、2 つの異なるタイプの問題を解決します。これらのパラダイムのいずれを使用するかの選択は、相互に依存するべきではありません。

したがって、タイトルの質問に対する私の答えは次のとおりです。いいえ、拡張メソッドの存在によって抽象基本クラスの魅力が低下することはありません。拡張メソッドの存在によって抽象基本クラスの魅力が低下すると考える場合、そもそも抽象基本クラスを正しく使用していません。

于 2009-03-16T19:53:29.143 に答える
3

いいえ、抽象クラスの誤用を減らすことができます。

抽象クラスには、サブクラスがオーバーライドできるデフォルトの実装/動作が含まれている必要があります。適切に因数分解された場合、これは、クラスの1つの動作のみをオーバーライドし、残りのデフォルトを使用できることを意味します。拡張メソッドは、これとはまったく異なるものを提供します。

于 2009-03-16T20:00:47.207 に答える
2

IList<T>私が欠けていたFind(Predicate)、Remove(Predicate) などを定義できるようになったので、拡張メソッドが好きです。抽象クラスの代わりになるとは言えないと思います。

また、一般的な動作を追加するための拡張メソッドも定義しました。オブジェクトまたは ToXml の ToJson 拡張メソッドが非常に便利です。

あなたの例で私が抱えている唯一の問題は、私は常に IsCurrentUser をメソッドではなくプロパティとして見ており、残念ながら拡張プロパティがないことです。しかし、私はつまらないです

それらは完全に無関係です。他の人が実装または継承する動作をモデル化したい場合は、抽象クラスを使用します。

于 2009-03-16T19:53:24.697 に答える
1

拡張メソッドは優れていますが、それらやその使用法を抽象クラスと比較することはできません。カプセル化とは何かを忘れないでください。これはOOPの柱の1つです...

于 2009-03-16T19:59:05.650 に答える
1

いいえ、抽象クラスはそれほど魅力的ではありません。抽象クラスは、オブジェクト階層に適切なパラダイムを提供します。

拡張メソッドが本当に役立つのは、既存のクラスにインスタンス メソッドを追加する必要があるが、コードを直接変更できない場合だけです。

于 2009-03-16T19:52:54.510 に答える
0

用途次第だと思います-

アセンブリ内のソースファイルやクラスの数を最小限に抑えるためのリファクタリングが主な関心事である場合は、そうです。拡張メソッドは間違いなく進むべき道であり、抽象クラスの使用はおそらく少なくなります。

ただし、抽象クラスが概念的に何を表すかをもっと気にする人にとっては、あまり変わっていません。「publicintgetCalories()」を抽象クラス「Food」に入れることは、コード組織のコンテキストではまだ意味があります。それを食べる人(食品のサブクラスを使用するコード)がいくつを定義するのはばかげているからです。それが持っているカロリー。

于 2009-03-16T19:57:07.090 に答える
0

一言で言えば:はい。抽象クラスは将来の実装に多くのことを課すという事実のために、一般的なアドバイスは、インターフェースを実装する抽象クラスを作成することであるようです(例えば、DBDataReader:IDataReader)。メソッドがオブジェクトの内部状態へのアクセスを必要としない限り、それを拡張メソッドとしてレンダリングしない理由はありません。コストをかけずに機能を利用できます。

于 2009-03-16T19:58:17.523 に答える
0

これが良い考えである場合は絶対にあると思います。Linqはメリットの優れた例ですが、別のメリットがあります。それはストリームです。

ストリームが抽象クラスである理由は、BeginRead、ReadByteなどのメソッドをサポートする必要があるためです。Streamはインターフェイスであり、これらのメソッドはすべて拡張メソッドである可能性があります。これにより、非ストリームクラスからの継承やストリーム機能の追加などが可能になり、「ストリームの内容をメモリバッファにダンプする」などの潜在的に有用なストリームメソッドを(より)自然に追加できるようになります。

于 2009-03-16T20:03:42.800 に答える
0

拡張メソッドから保護されたフィールドにアクセスする必要がない場合は、複数のインターフェイスを継承し、関連するすべての拡張機能をこの方法で取得できるため、それが私の知る限りの方法です (ただし、単一の抽象クラスからしか派生できません)。

于 2009-03-16T20:10:42.800 に答える
-1

私は .NET 2.0 より前のものを使用したことがないので、それができるとは思いもしませんでした。私には奇妙に思えます。インターフェイスは実装用ではありません。私はそれが紛らわしいと思います。また、表示する例はインターフェイスではなくクラスです。

于 2009-03-16T19:49:36.220 に答える