順番 - list 格納 c#




List<T>から継承しないのはなぜですか? (18)

私のプログラムを計画するとき、私はしばしば以下のような思考の連鎖から始めます:

サッカーチームは、サッカー選手のリストに過ぎません。 したがって、私はそれを次のように表現すべきです:

var football_team = new List<FootballPlayer>();

このリストの発注は、選手が選出された順番を表します。

しかし、後でチームには、記録されなければならない単なる選手のリストの他に、他の特性もあることが分かっています。 たとえば、今シーズンの得点の合計、現在の予算、統一色、チーム名を表すstringなど。

だから私は思う:

さて、サッカーチームは選手のリストに似ていますが、さらに名前( string )とランニング合計( int )を持っています。 .NETはフットボールチームを格納するためのクラスを提供しないので、私は自分のクラスを作成します。 最も似て関連性の高い既存の構造はList<FootballPlayer>ですので、私はそれを継承します:

class FootballTeam : List<FootballPlayer> 
{ 
    public string TeamName; 
    public int RunningTotal 
}

しかし、 List<T>から継承すべきではないというガイドラインがあることが判明しました。 私はこのガイドラインに2つの点で徹底的に混乱しています。

何故なの?

明らかに、 Listはパフォーマンスのために何らかの形で最適化されています 。 どうして? Listを拡張すると、どのようなパフォーマンス上の問題が発生しますか? 何が壊れますか?

私が見たもう1つの理由は、 ListがMicrosoftによって提供されていることです。私はそれを制御できないため、後で「公開API」を公開した後で変更することはできません 。 しかし、私はこれを理解するのに苦労します。 パブリックAPIとは何ですか、なぜ私は気にする必要がありますか? 私の現在のプロジェクトでこのパブリックAPIを使用することができない場合、このガイドラインを無視しても問題ありませんか? 私がListから継承しそれが公開されたAPIが必要な場合は、どのような困難がありますか?

それはなぜ重要なのでしょうか? リストはリストです。 何が変わる可能性がありますか? 私はおそらく何を変えたいのですか?

最後に、MicrosoftがListから継承しないようにしたら、どうしてクラスをsealedないのですか?

私は他に何を使うべきですか?

どうやら、カスタムコレクションの場合、MicrosoftではListクラスではなくCollectionクラスを提供しています。 しかし、このクラスは非常に裸であり、 例えばAddRangeような多くの有用なものはありません。 jvitor83の答えは、その特定のメソッドのパフォーマンスの理論的根拠を提供しますが、遅いAddRangeAddRangeなしより優れていませAddRangeか?

Collectionから継承するのは、 List継承するよりももっと仕事であり、私は何の利益も見ません。 確かにマイクロソフトでは何の理由もなく余計な作業をするようには言わなかったので、何かを誤解しているような気持ちにはならず、 Collectionを継承することは私の問題の正しい解決策ではありません。

私はIList実装などの提案を見てきました。 ちょうどいいえ。 これは何も得られない定型コードの数十行です。

最後に、 Listに何かをラップすることを提案します:

class FootballTeam 
{ 
    public List<FootballPlayer> Players; 
}

これには2つの問題があります。

  1. それは私のコードを不必要に冗長にします。 my_team.Players.Countではなくmy_team.Players.Countを呼び出す必要があります。 ありがたいことに、C#ではインデクシングを透明にするためのインデクサーを定義し、内部Listすべてのメソッドを転送することができます...しかし、それはたくさんのコードです! そのすべての仕事のために私は何を得ますか?

  2. それはまったく平凡ではありません。 サッカーチームは選手のリストを持っていません。 それ選手のリストです。 あなたは「John McFootballerがSomeTeamの選手に加わった」とは言わない。 あなたは「ジョンはSomeTeamに加わった」と言う。 "文字列の文字"に文字を追加しないで、文字列に文字を追加します。 あなたは図書を図書館の本に追加せず、図書を図書館に追加します。

「ボンネットの下で」何が起こるかは「Yを内部リストに追加する」と言うことができますが、これは世界を考える直感的な方法のように思えます。

私の質問(要約)

「論理的に」(つまり「人間の心に」)というデータ構造を表現する正しいC#の方法は、いくつかの鐘や笛のあるlistです。

List<T>から継承することは常に容認できませんか? いつ受け入れられますか? なぜ/なぜですか? List<T>から継承するかどうかを決定する際に、プログラマが考慮する必要があるのは何ですか?


最後に、リストに何かをラップすることを提案します:

それが正しい方法です。 「不必要に言葉遣い」は、これを見る悪い方法です。 my_team.Players.Countを記述すると、明示的な意味があります。 あなたは選手を数えたいと思う。

my_team.Count

..何も意味しない。 何を数えますか?

チームはリストではなく、単なるプレーヤーリスト以上のもので構成されています。 チームが選手を所有しているので、選手は選手の一員でなければなりません(メンバー)。

あなたが過度に冗長であることを本当に心配しているなら、いつでもチームからプロパティを公開することができます:

public int PlayerCount {
    get {
        return Players.Count;
    }
}

..されるもの:

my_team.PlayerCount

これは今や意味を持ち、 デメテルの法則を遵守しています。

複合再利用の原則を遵守することも考慮する必要があります。 List<T>継承することで、チームプレーヤーのリストであり、不要なメソッドを公開しているということになります。 これは間違っています - あなたが述べたように、チームは選手のリスト以上のものです:名前、マネージャー、ボードメンバー、トレーナー、医療スタッフ、給料キャップなどがあります。チームクラスに選手のリストが含まれていると、 「チームに選手のリストがある 」と言っているが、他のものも持つことができる。


データ構造を表す正しい C#の方法は何ですか...

Remeberは、 "すべてのモデルが間違っていますが、いくつかは有用です。" - ジョージEPボックス

「正しい方法」はなく、有用な方法だけです。

あなたやあなたのユーザーにとって便利なものを選んでください。 それでおしまい。 経済的に開発する、過剰にエンジニアリングしないでください。少ないコードを書くほど、デバッグするコードが少なくなります。(次の版を読む)。

- 編集済み

私の最善の答えは...それは依存するでしょう。Listから継承すると、このクラスのクライアントは、主にFootballTeamがビジネスエンティティのように見えるため、公開すべきではないメソッドに公開されます。

- 第2版

私は誠意をこめて、私が「オーバーエンジニアではない」というコメントに言及していることを覚えていない。私はKISS考え方が良いガイドだと信じていますが、Listからビジネスクラスを継承することは、抽象度のリークが原因で解決するよりも多くの問題を生み出すことを強調したいと思います。

一方、単純にListから継承するケースは限られていると考えられます。私が以前の版で書いたように、それは依存しています。それぞれのケースに対する答えは、知識、経験、個人的な好みの両方によって大きく影響されます。

答えについてもっと正確に考えるのを助けてくれた@kaiに感謝します。


文脈によって異なります

あなたのチームを選手のリストとみなすときは、フットボールチームの「アイデア」を1つの側面に投影しています。フィールドに表示されている人に「チーム」を減らします。この予測は、特定の状況でのみ正しいです。別の状況では、これは完全に間違っている可能性があります。あなたがチームのスポンサーになりたいと想像してみてください。だからあなたはチームのマネージャーと話をしなければなりません。このコンテキストでは、チームはそのマネージャのリストに投影されます。そして、これらの2つのリストは通常​​、あまり重複しません。他の文脈は、現在のプレーヤー対前のプレーヤーなどである。

不明確な意味

だから、チームを選手のリストとして考えることの問題は、そのセマンティックがコンテキストに依存し、コンテキストが変化したときにそれを拡張することができないということです。さらに、あなたが使っている文脈を表現するのは難しいです。

クラスは拡張可能です

メンバーを1人だけ持つクラス(例IList activePlayers)を使用する場合、メンバーの名前(およびそのコメント)を使用してコンテキストをクリアすることができます。追加のコンテキストがある場合は、メンバーを追加するだけです。

クラスはもっと複雑です

いくつかのケースでは、余分なクラスを作成することは過度の可能性があります。各クラス定義は、クラスローダーを介してロードする必要があり、仮想マシンによってキャッシュされます。これにより、実行時のパフォーマンスとメモリが必要になります。非常に具体的な状況があるときは、フットボールチームを選手のリストとみなしても問題ありません。しかし、この場合、実際には、IListそれから派生したクラスではなく、単にクラスを使用するべきです。

結論/考察

非常に具体的な状況がある場合、チームを選手のリストとみなしても問題ありません。例えば、メソッド内では、完全に書けばOKです

IList<Player> footballTeam = ...

F#を使用する場合は、型の省略形を作成することもできます

type FootballTeam = IList<Player>

しかし、文脈が広範であるか不明確であっても、これを行うべきではありません。これは、新しいクラスを作成するときに特に当てはまります。このクラスでは、将来使用されるコンテキストが明確ではありません。警告記号は、クラスに追加の属性(チーム、コーチなどの名前)を追加するときです。これは、クラスが使用されるコンテキストが固定されておらず、将来変更されるという明確な兆候です。この場合、チームを選手のリストとして考えることはできませんが、チームの属性として(現在アクティブで負傷していないなど)選手のリストをモデル化する必要があります。


デザイン>実装

公開するメソッドとプロパティは、設計上の決定です。 継承する基本クラスは実装の詳細です。 私はそれが元に戻って行く価値があると感じています。

オブジェクトとは、データとビヘイビアの集合です。

最初の質問は次のようにする必要があります。

  • 私が作成しているモデルでは、このオブジェクトはどのデータに含まれていますか?
  • このオブジェクトは、そのモデルでどのような動作をしますか?
  • これは将来どのように変わるでしょうか?

継承は「isa」(a)関係を意味し、一方、compositionは「has a」(hasa)関係を意味することに留意してください。アプリケーションの進化に伴ってどこに行かれるかを考慮しながら、自分の状況に適したものを選択してください。

具体的なタイプで考える前に、インターフェイスを考えることを検討してください。脳を「デザインモード」にする方が簡単だと感じる人もいます。

これは、毎日のコーディングにおいてこのレベルで意識的に誰もが何かをしているわけではありません。しかし、あなたがこの種のトピックを検討しているなら、あなたは設計水を踏みにじっています。それを知ることは解放することができます。

デザインの詳細を検討する

MSDNまたはVisual StudioのList <T>およびIList <T>を見てください。どのメソッドとプロパティが公開されているかを確認してください。これらのメソッドは、誰かがあなたの見解でFootballTeamにしたいと思うもののように見えますか?

footballTeam.Reverse()はあなたに意味がありますか?footballTeam.ConvertAll <TOutput>()はあなたが欲しいもののように見えますか?

これはトリックの質問ではありません。その答えは本当に「はい」であるかもしれません。List <Player>またはIList <Player>を継承/継承すると、あなたはそれらに悩まされています。それがあなたのモデルにとって理想的なら、それをしてください。

はいと判断したら、それは理にかなっていて、あなたのオブジェクトをコレクション/プレイヤーのリスト(ビヘイビア)として扱いたいので、ICollectionまたはIListを実装したいと思います。概念的には:

class FootballTeam : ... ICollection<Player>
{
    ...
}

あなたのオブジェクトにプレーヤー(データ)のコレクション/リストが含まれるようにするために、コレクションまたはリストをプロパティまたはメンバーにするには、是非行ってください。概念的には:

class FootballTeam ...
{
    public ICollection<Player> Players { get { ... } }
}

あなたは、プレイヤーの数を数えたり、プレイヤーに追加したり、プレイヤーを削除したりするのではなく、プレイヤーの集合を列挙できるようにしたいと思うかもしれません。IEnumerable <Player>は完全に有効なオプションです。

これらのインターフェースのどれもあなたのモデルではまったく役に立たないと感じるかもしれません。これはあまりありません(IEnumerable <T>は多くの状況で便利ですが)。それでも可能です。

どのような場合でも、これらのうちの1つが断然かつ間違っているとあなたに伝えようとする人は、間違っています。あなたにそれを正当に伝えようとする人は、すべての場合において正当に正しいと誤解されています。

実装に移る

データと動作を決定したら、実装に関する決定を下すことができます。これには、継承または合成を介して依存する具体的なクラスが含まれます。

これは大きなステップではないかもしれませんし、人々はしばしば2〜2秒であなたの頭の中でそれをすべて実行し、離れていくことが可能なので、設計と実装を融合させます。

思考実験

人工的な例:他の人が触れたように、チームは必ずしも「単なる」プレイヤーの集まりではありません。あなたはチームのマッチスコアのコレクションを維持していますか?あなたのモデルではチームはクラブと交換可能ですか?そうであれば、あなたのチームが選手の集まりであれば、おそらくスタッフの集まりやスコアの集まりでもあります。それで終わります:

class FootballTeam : ... ICollection<Player>, 
                         ICollection<StaffMember>,
                         ICollection<Score>
{
    ....
}

それにもかかわらず、C#のこの時点では、C#の "唯一"が単一の継承をサポートしているので、List <T>から継承することでこれらのすべてを実装することはできません。(このマルカリをC ++で試したことがあれば、これは良いことだと思うかもしれません。)コンストラクションを介して継承と1つのコレクションを実装することは、汚いと感じる可能性があります。また、ILIst <Player> .CountとIList <StaffMember> .Countなどを明示的に実装しないと、Countなどのプロパティが混乱するようになり、混乱するのではなく単なる苦痛になります。これがどこにあるのかを見ることができます。あなたがこの方向に向かうのが間違っていると感じるかもしれません(正直か間違って、この方法で実装した場合、あなたの同僚もまたそうするかもしれません!)。

短い答え(遅すぎる)

コレクションクラスから継承しないことに関するガイドラインはC#固有ではなく、多くのプログラミング言語で使用できます。知恵は法律ではありません。1つの理由は、実際には、理解力、実装可能性、および保守性の観点から、構成が継承を勝ち取ることが多いと考えられるからです。特に、時間がたつとコード内のオブジェクトの正確なデータと振る舞いを熟考しない限り、有用で一貫した "isa"関係よりも有用で一貫した "hasa"関係を見つけることは、実世界/変更。コレクションクラスから継承することを常に排除する必要はありません。それは示唆的かもしれません。


うわー、あなたの投稿にはたくさんの質問とポイントがあります。 あなたがマイクロソフトから得た理性の大部分は、正確なポイントです。 List<T>に関するすべてのものから始めましょう

  • List<T> 高度に最適化されています。 その主な用途は、オブジェクトのプライベートメンバーとして使用されることです。
  • class MyList<T, TX> : List<CustomObject<T, Something<TX>> { ... }ように、友好的な名前を持つクラスを作成することがあります。 これで簡単にvar list = new MyList<int, string>();
  • CA1002:ジェネリックリストを公開しないでください :基本的に、このアプリケーションを唯一の開発者として使用する予定がある場合でも、優れたコーディング手法を使用して開発する価値があります。 コンシューマにインデックス付きのリストが必要な場合は、 IList<T>としてリストを公開することはできIList<T> 。 これで、後でクラス内の実装を変更しましょう。
  • MicrosoftはCollection<T>非常に汎用的なものにしました。なぜなら、その名前はそれをすべて表しています。 単なるコレクションです。 IList<T>を実装していて List<T>を実装していない SortedCollection<T>ObservableCollection<T>ReadOnlyCollection<T>などのより正確なバージョンがありIList<T>
  • Collection<T>は、メンバ(つまり、Add、Removeなど)が仮想であるためオーバーライドすることを可能にします。 List<T>はそうではありません。
  • あなたの質問の最後の部分にスポットがあります。 サッカーチームは単に選手のリストではないので、選手のリストを含むクラスでなければなりません。 コンポジションと継承を考えよう。 サッカーチームに選手(選手)のリストがあり、選手のリストではありません。

私がこのコードを書いていたら、クラスはおそらく次のようになります:

public class FootballTeam
{
    // Football team rosters are generally 53 total players.
    private readonly List<T> _roster = new List<T>(53);

    public IList<T> Roster
    {
        get { return _roster; }
    }

    // Yes. I used LINQ here. This is so I don't have to worry about
    // _roster.Length vs _roster.Count vs anything else.
    public int PlayerCount
    {
        get { return _roster.Count(); }
    }

    // Any additional members you want to expose/wrap.
}

ここにいくつかの良い答えがあります。 私はそれらに次の点を追加します。

「論理的に」(つまり「人間の心に」)というデータ構造を表現する正しいC#の方法は、いくつかの鐘や笛のあるリストです。

空白を埋めるためにサッカーの存在に精通しているコンピュータプログラマー以外の10人の人々に質問してください。

A football team is a particular kind of _____

もが「鐘や笛が聞こえるフットボール選手のリスト」とか、「スポーツチーム」や「クラブ」や「組織」といった人はいませんか? サッカーチームが特定の種類の選手であるというあなたの考えは、あなたの人間の心とあなたの人間の心だけにあります。

List<T>メカニズムです。 サッカーチームはビジネスオブジェクトです。つまり、プログラムのビジネスドメインにある概念を表すオブジェクトです。 それらを混ぜないでください! サッカーチームは一種のチームです。 それ名簿を持ってます、名簿は選手のリストです選手は選手のリストの特定の種類ではありません。 名簿選手のリストです。 List<Player>という名前のRosterというプロパティを作成します。 また、あなたがサッカーチームについて知っているすべての人が選手を選手から削除すると信じている場合を除いて、あなたがそれをしている間にReadOnlyList<Player>してください。

List<T>から継承することは常に容認できませんか?

誰に受け入れられないのですか? 私? いいえ。

いつ受け入れられますか?

List<T>仕組み拡張するメカニズムを構築しているとき。

List<T>から継承するかどうかを決定する際に、プログラマが考慮する必要があるのは何ですか?

メカニズムビジネスオブジェクトを構築していますか?

しかし、それは多くのコードです! そのすべての仕事のために私は何を得ますか?

List<T>関連するメンバーの50回以上の転送メソッドを記述するために、あなたはあなたの質問を入力するより多くの時間を費やしました。 あなたは明らかに冗長さを恐れることはありません。ここではごく少量のコードについて話しています。 これは数分の作業です。

更新

私はもう少し考えをしましたが、選手のリストとしてサッカーチームをモデル化しない別の理由があります。 実際、サッカーチームに選手のリストがあるとモデル化するのは悪い考えかもしれません。 選手のリストを持つチームの問題は、あなたが持っているものが、チームの一瞬の スナップショットだということです。 あなたのビジネスケースはこのクラスのためにはわかりませんが、サッカーチームを代表するクラスがあれば、「2003年から2013年の間にSeahawksのプレーヤーが負傷したためにゲームを逃した人の数」のような質問をしたいと思います。 または「以前に他のチームのためにプレーしたデンバー選手が、ヤードの前年比で最も大きな増加をしたのは何ですか? 「 今年、ピガーたちは一生懸命に行きましたか?

つまり、サッカーチームは、選手が募集、負傷、引退などの歴史的事実のコレクションとしてよくモデル化されているようです。明らかに、現在の選手名簿は、おそらく、もっと歴史的な視点を必要とするこのオブジェクトでやりたいことが他にもあるかもしれません。


まず第一に、使いやすさと関係しています。 継承を使用する場合、 Teamクラスはオブジェクト操作用に設計された動作(メソッド)を公開します。 たとえば、 AsReadOnly()またはCopyTo(obj)メソッドは、チームオブジェクトに意味をなさない。 AddRange(items)メソッドの代わりに、おそらくよりわかりやすいAddPlayers(players)メソッドが必要です。

LINQを使用する場合は、 ICollection<T>IEnumerable<T>などの汎用インターフェイスを実装する方が理にかなっています。

言及したように、構図は正しいことです。 プライベート変数として選手のリストを実装するだけです。


人々が言えるようにするか

myTeam.subList(3, 5);

全く意味をなさない?そうでなければ、それはリストであってはならない。


あなたのクラスのユーザーが**リストにあるすべてのメソッドとプロパティを必要とする場合は、そのクラスからクラスを派生させる必要があります。必要がない場合は、リストを囲み、クラスのユーザーが実際に必要とするメソッドのラッパーを作成します。

これは、パブリックAPI、または多くの人が使用するその他のコードを記述する場合、厳密なルールです。このルールは、小さなアプリと2人以下の開発者がいる場合は無視できます。これにより、時間を節約できます。

小さなアプリの場合は、あまり厳密でない言語を選択することも考えられます。Ruby、JavaScript - 少ないコードを書くことができるもの。


あなたの質問を書き直しましょう。異なる視点からの主題を見るかもしれません。

私がサッカーチームを代表する必要があるとき、私はそれが基本的に名前であることを理解する。「イーグルス」のように

string team = new string();

その後、チームにも選手がいることが分かりました。

なぜ私はストリング型を拡張して、選手のリストも保持できないのですか?

問題へのあなたの入り口は任意です。チーム何を持っているのか(プロパティ)が何でないかを考えてみてください。

その後、他のクラスとプロパティを共有するかどうかを確認できます。そして相続について考える。


これは私に "Is a"対 "a has"のトレードオフを思い出させる。スーパークラスから直接継承する方が簡単な場合もあります。それ以外の場合は、スタンドアロンクラスを作成し、メンバ変数として継承したクラスを追加する方が理にかなっています。それでもクラスの機能にアクセスすることはできますが、インタフェースまたはクラスから継承した他の制約にはバインドされません。

あなたはどちらですか?多くのものと同様に、それは文脈にもよります。私が使用するガイドは、別のクラスから継承するためには、本当に "is a"の関係でなければならないということです。したがって、BMWと呼ばれるクラスを書くと、BMWは本当に車なので、Carから継承することができます。馬は実際には哺乳類であり、哺乳類の機能性は馬に関連しているはずであるため、馬のクラスは哺乳動物のクラスを継承することができます。しかし、チームがリストであると言うことができますか?私が言うことから、チームのようには見えません。本当に「リスト」です。したがって、この場合、Listをメンバー変数として使用します。


それはあなたの "チーム"オブジェクトの動作に依存します。それがコレクションのように振る舞うのであれば、最初にプレーンなListで表現することは可能かもしれません。次に、リストを反復するコードを複製し続けることに気づくでしょう。この時点で、プレイヤーのリストをラップするFootballTeamオブジェクトを作成するオプションがあります。FootballTeamクラスは、プレイヤーのリストを反復するすべてのコードのホームになります。

それは私のコードを不必要に冗長にします。my_team.Countではなくmy_team.Players.Countを呼び出す必要があります。ありがたいことに、C#ではインデクシングを透明にするためのインデクサーを定義し、内部リストのすべてのメソッドを転送することができます...しかし、それはたくさんのコードです!そのすべての仕事のために私は何を得ますか?

カプセル化。あなたのクライアントは、FootballTeamの内部で何が起こっているのかを知る必要はありません。あなたのすべてのクライアントが知っている限り、それはデータベース内のプレイヤーのリストを調べることで実装されるかもしれません。彼らは知る必要はなく、これによりデザインが改善されます。

それはまったく平凡ではありません。サッカーチームは選手のリストを持っていません。それは選手のリストです。あなたは「John McFootballerがSomeTeamの選手に加わった」とは言わない。あなたは「ジョンはSomeTeamに加わった」と言う。"文字列の文字"に文字を追加しないで、文字列に文字を追加します。あなたは図書を図書館の本に追加せず、図書を図書館に追加します。

正確に:)あなたはfootballTeam.List.Add(ジョン)ではなく、footballTeam.Add(ジョン)と言うでしょう。内部リストは表示されません。


サッカーチームサッカー選手のリストではありません。サッカーチーム、サッカー選手のリストで構成されています!

これは論理的に間違っています:

class FootballTeam : List<FootballPlayer> 
{ 
    public string TeamName; 
    public int RunningTotal 
}

これは正しいです:

class FootballTeam 
{ 
    public List<FootballPlayer> players
    public string TeamName; 
    public int RunningTotal 
}

彼らList<T>が「最適化されている」と言うとき、私は彼らは少し高価な仮想メソッドのような機能を持っていないことを意味したいと思う。したがって、問題が公開API公開List<T>れると、ビジネスルールを適用したり、後でその機能をカスタマイズする能力が低下します。しかし、この継承クラスをプロジェクト内で内部的に使用している場合(APIとして何千もの顧客/パートナー/他のチームに潜在的に露出するのではなく)、時間を節約すればOKかもしれません。重複する。継承の利点は、近い将来にカスタマイズされることのないダンプラッパーコードをたくさん削除することです。また、あなたのクラスが明示的に同じセマンティクスを持つようにしたい場合List<T>List<T> あなたのAPIの寿命のために、それはまたOKかもしれません。

私はしばしば、FxCopのルールがそう言っているという理由だけで、たくさんの余分な仕事をしている人が多く見られます。多くの場合、これはパターンパルオザの奇妙さを設計するためのコードに変わります。多くのガイドラインと同様に、例外持つことができるガイドラインとして扱います。


私の汚れた秘密:私は人々の言うことを気にせず、私はそれをする。.NET Frameworkは、 "XxxxCollection"(私の頭の一番上にあるUIElementCollection)で広がっています。

だから私が言っていることを止めるもの:

team.Players.ByName("Nicolas")

私がそれをよりよく見つけたとき

team.ByName("Nicolas")

さらに、私のPlayerCollectionは、 "Club"のような他のクラスでもコードの重複なしに使用される可能性があります。

club.Players.ByName("Nicolas")

昨日のベストプラクティスは、明日のものではないかもしれません。ほとんどのベストプラクティスには理由がありません。ほとんどのものがコミュニティ間でのみ合意しています。あなたが自分自身に尋ねるときにあなたを責めるかどうかコミュニティに尋ねるのではなく、読みやすく保守しやすいものは何ですか?

team.Players.ByName("Nicolas") 

または

team.ByName("Nicolas")

本当に。疑いはありますか?おそらく、あなたの実際のユースケースでList <T>を使用できないような他の技術的な制約を払う必要があるかもしれません。しかし、存在してはならない制約を追加しないでください。なぜMicrosoftがその理由を文書化しなかったなら、それは確かにどこからも来ていない "ベストプラクティス"です。


私はあなたの一般化に同意しないと思います。チームは単なるプレイヤーの集まりではありません。チームには、名前、エンブレム、管理/管理スタッフの集まり、コーチングクルーの収集、選手の集まりなど、それに関する情報が非常に多くあります。だから、あなたのFootballTeamクラスは3つのコレクションを持ち、コレクション自体ではありません。現実の世界を適切にモデル化することであるならば。

特殊化されたStringCollectionのように、オブジェクトが内部ストアに追加または削除される前に検証やチェックなどの他の機能を提供するPlayerCollectionクラスを考えることができます。

おそらく、PlayerCollectionの考え方はあなたの好みのアプローチに合っていますか?

public class PlayerCollection : Collection<Player> 
{ 
}

そして、FootballTeamは次のようになります。

public class FootballTeam 
{ 
    public string Name { get; set; }
    public string Location { get; set; }

    public ManagementCollection Management { get; protected set; } = new ManagementCollection();

    public CoachingCollection CoachingCrew { get; protected set; } = new CoachingCollection();

    public PlayerCollection Players { get; protected set; } = new PlayerCollection();
}

私はちょうどEiffelの発明者であり、契約によるデザインのBertrand Meyerがまぶたを打つことなしにTeam継承するだろうと付け加えましたList<Player>

オブジェクト指向のソフトウェア構築の彼の著書では、長方形のウィンドウに子ウィンドウを持つことができるGUIシステムの実装について議論しています。彼は単に持っているWindow両方を継承Rectangleし、Tree<Window>実装を再利用します。

しかし、C#はエッフェルではありません。後者は、複数の継承と機能の名前の変更をサポートしています。C#では、サブクラス化すると、インタフェースと実装の両方を継承します。実装をオーバーライドできますが、呼び出し規約はスーパークラスから直接コピーされます。エッフェル塔では、しかし、あなたは、publicメソッドの名前を変更することができますので、あなたが名前を変更することができますAddし、RemoveHireし、FireあなたにTeam。インスタンスTeamがアップキャストされているList<Player>場合、呼び出し元はそれを使用AddRemoveて変更しますが、仮想メソッドHireFireが呼び出されます。


class FootballTeam : List<FootballPlayer> 
{ 
    public string TeamName; 
    public int RunningTotal;
}

これまでのコードは、路上でフットボールをしている人たちの集まりを意味しています。 何かのようなもの:

とにかく、このコード(私の答えから)

public class FootballTeam
{
    // Football team rosters are generally 53 total players.
    private readonly List<T> _roster = new List<T>(53);

    public IList<T> Roster
    {
        get { return _roster; }
    }

    public int PlayerCount
    {
    get { return _roster.Count(); }
    }

    // Any additional members you want to expose/wrap.
}

意味:これは管理、選手、管理者などがいるサッカーチームです。

これはあなたのロジックが写真にどのように表示されるかです...





inheritance