1. ホーム
  2. c#

[解決済み] なぜList<T>を継承しないのですか?

2022-03-18 01:24:33

質問

番組の企画を考えるとき、私はよく次のような思考の連鎖からスタートします。

<ブロッククオート

アメフトチームは、アメフト選手のリストに過ぎない。したがって、私はそれを表現する必要があります。

var football_team = new List<FootballPlayer>();

このリストの順番は、ロスターに記載されている選手の順番を表しています。

しかし、チームには単なる選手のリスト以外にも、記録しなければならないプロパティがあることに後で気づきました。例えば、今シーズンの得点の累計、現在の予算、ユニフォームの色、そして string チーム名を表すなど。

では、考えます。

さて、サッカーチームは選手のリストと同じですが、さらに、名前(a string )、得点の累計( int ). .NETにはサッカーチームを格納するクラスがないので、自分でクラスを作ることにします。最も似ていて関連性のある既存の構造は List<FootballPlayer> ということで、それを継承することにします。

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

しかし、それが判明したのは を継承してはいけないというガイドラインがあります。 List<T> . 私は2つの点でこのガイドラインに徹底的に困惑しています。

なぜダメなのか?

どうやら List は、何らかの形でパフォーマンスに最適化されています。 . どのように?を拡張した場合、どのようなパフォーマンスの問題が発生するのでしょうか? List ? 具体的に何が壊れるのでしょうか?

もう一つの理由は、私が見たところ List はマイクロソフトが提供するものであり、私にはコントロールできないので 公開APIを公開した後では、後から変更することはできません。 . しかし、これを理解するのに苦労しています。パブリックAPIとは何なのか、なぜ気にしなければならないのか。もし私の現在のプロジェクトがこのパブリックAPIを持たず、今後も持つ可能性がないのであれば、このガイドラインを無視して大丈夫なのでしょうか?もし私が List 公開APIが必要なことがわかりましたが、どのような困難があるのでしょうか?

なぜそれが重要なのか?リストはリストです。何が変わる可能性があるのか?何を変えたいと思うことがあるのでしょうか?

そして最後に、もしマイクロソフトが私に List なぜ sealed ?

他に何を使えばいいのでしょうか?

どうやらカスタムコレクションのために、マイクロソフトが提供する Collection クラスの代わりに拡張する必要があります。 List . しかし、このクラスは非常に素っ気なく、あまり便利なものは持っていません。 のような AddRange , 例えば jvitor83の回答 は、その特定の方法に対するパフォーマンスの根拠を提供していますが、どのように遅い AddRange がないよりはましですが AddRange ?

を継承しています。 Collection を継承するよりもはるかに多くの作業を必要とします。 List そして、何のメリットもありません。確かにマイクロソフトは意味もなく余計なことをしろとは言わないでしょうから、何か誤解しているような気がしてなりません。 Collection は、実は私の問題に対する正しい解決策ではないのです。

を実装するなどの提案を見たことがあります。 IList . ただ、ダメなんです。これは何十行もの定型的なコードで、私には何の得にもなりません。

最後に List を何かで囲む。

class FootballTeam 
{ 
    public List<FootballPlayer> Players; 
}

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

  1. コードが無駄に冗長になる。私は今 my_team.Players.Count ではなく、単に my_team.Count . ありがたいことに、C#ではインデックスの作成を透過的にするためにインデクサを定義し、内部の List ... しかし、それは多くのコードです しかし、これは多くのコードです!私はその仕事のために何を得るのでしょうか?

  2. ただ、意味がないんです。サッカーチームは選手のリストを持っていません。それは 選手のリストです。John McFootballer has joined SomeTeam's players"とは言わないんですね。あなたは、"John has joined SomeTeam"と言っています。文字列の文字に文字を追加するのではなく、文字列に文字を追加するのです。図書館の本に本を追加するのではなく、図書館に本を追加するのです。

しかし、これは非常に直感的でない考え方だと思います。

私の質問(要約)

論理的に(つまり、人間の心にとって)単なるデータ構造であるデータ構造を表現する正しいC#の方法は何ですか? listthings を、少しベルとホイッスルを使って?

を継承しているのでしょうか? List<T> 常に受け入れられないのでしょうか?どのような場合に受け入れられますか?なぜ/なぜダメなのか?を継承するかどうかを決めるとき、プログラマは何を考慮しなければならないか? List<T> を使うかどうか?

どのように解決するのですか?

良い回答がいくつかありますね。私はそれらに以下の点を付け加えたいと思います。

<ブロッククオート

論理的には(つまり、人間の心にとっては)単なるリストであるデータ構造を、C#で正しく表現する方法は何でしょうか。

サッカーの存在を知っている、コンピューター・プログラマーではない10人に、空欄を埋めるように尋ねてみてください。

<ブロッククオート

サッカーチームは、特定の種類の_____である。

した。 だれでも それとも、全員が「スポーツチーム」「クラブ」「組織」と言ったのでしょうか? アメフトチームが 特定の種類の選手のリスト は、あなたの人間の頭の中にあるものであり、あなたの人間の頭の中だけのものです。

List<T> 機構 . サッカーチームは ビジネスオブジェクト -- にある何らかの概念を表すオブジェクトです。 ビジネスドメイン プログラムの 混ぜるな危険! サッカーチーム は、一種の チーム; それは を持っています。 ロスター、名簿 は、選手のリスト . ロスターは 特定の種類の選手リスト . ロスター 選手のリストです。というプロパティを作って Roster というのは List<Player> . そして、それを ReadOnlyList<Player> ただし、サッカーチームについて知っている人なら誰でも、登録選手から選手を削除することができると考えている場合は除きます。

<ブロッククオート

を継承しているのか? List<T> は、常に受け入れられないのでしょうか?

誰にとって受け入れ難いか?私?

どのような場合に受け入れられるのでしょうか?

という仕組みを作る場合 を拡張します。 List<T> 機構 .

を継承するかどうかを決定するとき、プログラマは何を考慮しなければならないか? List<T> それとも

を作っているのでしょうか? 機構 または ビジネスオブジェクト ?

でも、これだけのコードがあるんですよ! でも、これだけのコードを書いてどうなるんだ?

の関連するメンバに転送するメソッドを書くのにかかる時間よりも、質問をタイプするのにかかる時間の方が長いのです。 List<T> を50回繰り返す。あなたは明らかに冗長性を恐れていませんし、ここで話しているのはごくわずかなコードのことです。

アップデイト

さらに考えてみたところ、サッカーチームを選手のリストとしてモデル化しないほうがいい理由がもうひとつありました。実際、フットボールチームを 有する のリストもあります。チームを選手のリストと見なす/持つことの問題は、あなたが得たものが スナップショット チームの ある時点の . このクラスのビジネスケースがどのようなものか知りませんが、もし私がフットボールチームを代表するクラスを持っていたら、「2003年から2013年の間に何人のシーホークスの選手が怪我で試合に出られなかったか」「以前他のチームでプレーしていたデンバーの選手で、前年比で最も走行ヤードが増加したのは誰か」といった質問をしたいところです。 今年のピガーは全勝だったのか? "。

つまり、サッカーチームというのは、よくモデル化されているように思います。 歴史的事実の集合体 例えば、選手がいつ採用されたか、負傷したか、引退したか、など。もちろん、現在の選手名簿は重要な事実であり、前面に押し出すべきものですが、このオブジェクトでやりたいことの中には、もっと歴史的な視点が必要なものがあるかもしれません。