質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
87.20%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

解決済

継承した場合のstatic変数/関数について

nono1234
nono1234

総合スコア25

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

5回答

0評価

1クリップ

3319閲覧

投稿2021/02/01 14:26

編集2021/02/02 15:10

継承した場合のstatic変数/関数の扱いについて悩んでいます

C#

//Program.cs using System; using System.Collections.Generic; using System.Linq; namespace ConsoleApp1 { class Program { static void Main(string[] args) { var BoyDict = new Dictionary<string, int>() { { "Taro", 12 }, { "Jiro", 13 }, { "Sabu", 14 } }; var GirlDict = new Dictionary<string, int>() { { "Ichi", 15 }, { "Ni", 16 }, { "San", 17 } }; // DictionaryからBoyインスタンスを作成 var BoyList = BoyDict.Select(_boy => new Boy(_boy.Key, _boy.Value)).ToList(); Console.WriteLine(String.Join(",", Boy.NameList)); // Taro,Jiro,Sabuが出るし、それで正しい Console.WriteLine(String.Join(",", Girl.NameList)); // この時点はListが空であってほしいがTaro,Jiro,Sabuが出る // DictionaryからGirlインスタンスを作成 var GirlList = GirlDict.Select(_girl => new Girl(_girl.Key, _girl.Value)).ToList(); Console.WriteLine(String.Join(",", Boy.NameList)); // Taro,Jiro,Sabuが出てほしいがTaro,Jiro,Sabu,Ichi,Ni,Sanが出る Console.WriteLine(String.Join(",", Girl.NameList)); // Ichi,Ni,Sanが出てほしいが、Taro,Jiro,Sabu,Ichi,Ni,Sanが出る } } }

C#

// Person.cs using System; using System.Collections.Generic; using System.Text; namespace ConsoleApp1 { abstract public class Person { string Name; int Age; public static List<string> NameList = new List<string>(); public Person(string Name, int Age) { this.Name = Name; this.Age = Age; NameList.Add(Name); } public static void SaveNameList(){ // NameListをcsvにする処理。これはBoy,Girlで共通 } } public class Boy : Person { public Boy(string Name, int Age) : base(Name, Age) { } } public class Girl : Person { public Girl(string Name, int Age) : base(Name, Age) { } } }

このようにPersonクラスを継承したBoyクラスとGirlクラスがあります.
Personクラスはインスタンス生成時に自身の場のNameListに生成された人の名前のリストを自動的に保存します.

こんな感じで,BoyとGirlでそれぞれNameListを持たせたいのですが,実際にこのコードを実行すると,2つ問題があります.
1:Person Boy GirlのNameListが同一のものになっているので別々に持たせたいです.
Boy Girl側でPublic new static List<string> NameListをしたら持たせられるのですが,Person側でできないでしょうか?
2:staticメソッドのSaveNameListもPersonクラスのNameListを参照するため,想定の動作をしません.
どのようにすればよいでしょうか?

また,そもそも設計思想が間違っているのでしょうか?
(NameListをPersonのstaticにすべきでないなど)

2021/2/2追記:

みなさまから多くの意見を頂き本当にありがとうございます.
まず最初に謝らせていただくこととして,このコード例は問題を具体化したかったために,作った
ものです.
やりたかったことはabstract classを継承した子クラスが,それぞれstaticな変数を持つ時に親クラスでstatic宣言した場合,親クラスのものと同一のものになるのではなく,子クラスでstaticなものを持っていてほしいということです.(Personの場,Boyの場,Girlの場があり,それぞれに同様の意味を持つstaticな変数を持たせたい)
そして,staticな関数の中で,自身の場を参照したいような時にも親クラスの場を参照してしまうという問題点を解決したいというものです.
適当な例としてstaticなNameListと,staticなNameListをCSV出力する関数を挙げたつもりでしたが不適切でした.確かにPersonがNameListを持つべきではありません

例えば染色体(Chromosomes)をPersonは持っています.これはどのPersonにもあり,インスタンスごとに違うものでもないのでstaticです(もしかしてここの理解が間違っているのでしょうか?).ただし,Personの染色体はこの時点では不定なので,定義だけされています.
Personを継承したBoyも染色体を持ちます.Boyの場合はxyです.Girlの場合xxです.

この時Boy.Chromosomos="xy", Girl.Chromosomos="xx"だと思うので,親と,それを継承した子1, 子2......で別のstaticな変数が欲しいという場面はあると思います

またややこしい例を持ち出して申し訳ありませんが,私がNameListを例として挙げてしまったがために本筋と外れた議論になってしまったので追記させていただきます.

//追記その2
staticにすべき変数論に発散してしまったので,一度締めさせていただきます。
みなさまのご意見非常に勉強になりました.
頂いた意見の中では

  • 抽象プロパティで定義する(もしかすると実際にはできない?)
  • PersonMangerクラスで管理する

が特に参考になりました。

今回の例では具体的過ぎて,「Personであったらそのように実装すべきでない」という意見を数多く頂きましたが,実際クラスで一括管理したいstaticなものがあると思うのですが,どうやらstaticの認識がみなさまのものと違っているようです.もういちど勉強します・

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

気になる質問をクリップする

クリップした質問は、後からいつでもマイページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

dodox86

2021/02/01 14:35

> また,そもそも設計思想が間違っているのでしょうか? > (NameListをPersonのstaticにすべきでないなど) 設計思想が間違っていると思いますし、まずはstaticにしなければ良いのでは?なぜ、staticにしようと考えましたか? staticは、インスタンスに関わらずクラスの全てで共通になります。
dodox86

2021/02/01 14:38

「Person」と、クラス名から想定するカバー範囲はひとりの人物を指すようなイメージに対して、NameListと複数人を想定するフィールドを持つことも、設計思想が間違っている感があります。
nono1234

2021/02/01 14:48

>「Person」と、クラス名から想定するカバー範囲はひとりの人物を指すようなイメージに対して、>NameListと複数人を想定するフィールドを持つことも、設計思想が間違っている感があります。 この部分は自分でもなんとなくそうではないかと思います. 呼び出し側で管理すべき案件だというのは理解しています. メタクラス的なものが欲しいのですが...
Zuishin

2021/02/01 15:02 編集

そもそも辞書を使って名前をキーにするところから無茶苦茶。設計思想は合っている間違っているのレベルではなく、思想が無いようにしか見えません。NameList など何の役に立つのかわからないリストを static で保持する理由はないし、百歩譲ってどうしても必要な場面が仮にあったとしても var boyNameList = BoyList.Select(a => a.Name).ToList() で十分です。BoyList から Name にアクセスすればいいだけなので、boyNameList が必要な場面がまったく想像つきませんが。
Zuishin

2021/02/01 15:13

それでもどうしても質問のようなことがしたいなら、Person に実装するのではなく Boy と Girl にそれぞれ実装すればできます。多態性を使いたいならインターフェースを作りましょう。
退会済みユーザー

退会済みユーザー

2021/02/01 15:33 編集

そもそも性別毎にクラス作る必要も無いと思うんですが、Personに性別のプロパティ追加すればいいんじゃないですかね。 名簿のようなものをイメージする時、一人分のデータを表現するのにどういう項目が必要になるか考えてみるといいと思います。そこにNameListが必要でしょうか?あったら変ですよね。
nono1234

2021/02/01 15:39

辞書からインスタンス生成したのは,例としてさらっと書きたかったのですみません 確かにNameListが頻繁に呼ばれないのであれば,BoyList.Select(a => a.Name).ToList() で十分です. ありがとうございます. インターフェース作っても,結局BoyとGirlでSaveNameListを記述しなければならないのではないのでしょうか(インターフェースのデフォルト処理で行けるのでしょうか?)
nono1234

2021/02/01 15:46

@radianさん ここに書かれている部分だけで言えば確かにそうなのですが,例えばBoyだけに特定の関数持たせたかったりBoyとGirlで関数の名前同じだけど別のことをさせたいというようなこともあるので,BoyとGirlは分けたいです. NameListをPersonに持たせるべきではないというご指摘に関してはおっしゃる通りだとおもいます.
退会済みユーザー

退会済みユーザー

2021/02/01 15:52 編集

> 例えばBoyだけに特定の関数持たせたかったりBoyとGirlで関数の名前同じだけど別のことをさせたいというようなこともあるので そういう事なら、クラス作らざるを得ないかもしれませんね。抽象メソッドを使用すると良いかもしれません。
nono1234

2021/02/01 15:56 編集

ここに関しては,性別をPersonにいれたら良いというご指摘に対しての反論のつもりでした ご配慮ありがとうございます
退会済みユーザー

退会済みユーザー

2021/02/01 15:56

提示されてるコードだけからは、さすがに実装するつもりのことはエスパーじゃないので読み取れません。
Zuishin

2021/02/02 11:19

追記を見ましたが、このような場合、Boy のコンストラクタで xy に設定し、Girl のコンストラクタで xx に設定します。 まず static を使う状況を無理やり考え出そうとしているところが間違っています。コードは問題を解決するものであり、思いつきの使いたいコードを無理やり使うものではありません。問題がないのならば色物は放置してその前にすることがあると思います。
nono1234

2021/02/02 12:00

追記に関してはこのページでの議論が私のNameListの例により異なった方向に進んでいたために提示したもので,この質問を投稿した時から質問の本質は変わっていません 「staticな場を持つ」クラスを継承したいが,そのstaticな場は別で持ちたいというものです.インターフェースに近いかと思いますが,その場に対して行いたい行為は一律なのでインターフェースほど抽象的でなくてもよいという感じです
Zuishin

2021/02/02 12:23

ただなんとなく「持ちたい」というのがそもそもの間違いで、プログラミングとはかけ離れているという意味です。
退会済みユーザー

退会済みユーザー

2021/02/02 12:27 編集

結局のところ、何をもって解決とするかがさっぱり見えないのですが。後付けて色々条件足されるとキリがないです。最初の質問の答えはきちんと返している回答がついてるので、一度ベストアンサー付けて締めて設計し直したらどうです?それで作り込んでいって、問題が出てきたら改めて質問すればよいでしょう。
nono1234

2021/02/02 14:52

@Zuishinさん 持ちたいというのは,それを親の方で一括管理した記述をすることが出来れば,子の方で定義する必要がないからです(同じことを二度書くべきではないというのはプログラミングの原則かと思います)
nono1234

2021/02/02 14:55

@radianさん 確かに発散してしまっているところがあるので,いちど締めたいと思います
Zuishin

2021/02/02 15:58 編集

子の方で定義する必要など最初からないので親でも定義しなくて大丈夫です。一度も定義する必要のないものを一度定義しようとするのはプログラミングの原則ではありません。
actorbug

2021/02/02 21:01

「あるオブジェクトが特定のインスタンス変数を持つべき」だと指定したいのであれば、 クラスでそのように指定するのが普通です。 同様に、「あるクラスが特定のstatic変数を持つべき」だと指定したいのであれば、 クラスのクラスであるメタクラスで指定するのが普通でしょう。 それをクラスの継承で実現しようとしているのが、そもそもの誤りではないでしょうか。 そういうことをやりたいのであれば、メタクラスの存在する別言語に移行することをお勧めします。

まだ回答がついていません

会員登録して回答してみよう

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
87.20%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問

同じタグがついた質問を見る

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

継承

継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。