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

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

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

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

Q&A

解決済

3回答

422閲覧

C#リストを使ったクラスの書き方

irm

総合スコア25

C#

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

0グッド

0クリップ

投稿2018/12/26 15:13

編集2018/12/27 04:51

前提・実現したいこと

一つのcsにクラスなしで書いていたプログラムを、2つのクラス(Person,Calculator)とそれを操るメインのプログラムに分けたい。

やろうとしていることは、BtnDivide_Click内の通りです。このコードをクラス化Calculatorする
クッキーの総数を、名前リストlistOfPersonの数で割り、割り切れなかった余り(15/4= 3..3のあまり3など)についてもリスト上の上から順番に一つずつ割り当てていき、結果をxamlのリストボックスに表示させる。

Personクラスでは、リストへの追加とソートを設計
Calculatorクラスでは計算部分を設計
プログラムクラスで、まとめて

発生している問題・エラーメッセージ

クラスなしで書いていたプログラムです。初心者なので拙いコードながら、リストのソートの前まではうまく行って動作もしていましたが、リストをソートする必要がでてきて、クラスを作る必要がでてきたため、書き換えなければならなくなりました。
しかし、クラス化する際のクラス内のメソッドにする書き方がついていけません。
例えばメインプログラムでオブジェクト化する際に、リストのオブジェクトに相当するものは何になるのかや、リストをAddする動作はクラス内なのかメインのプログラムなのか等です…。またリストを使ったクラスの例があるとヒントになるのですが見つけられなかったです。

エラーメッセージ

### 該当のソースコード c# namespace renshu { /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } List<Person> listOfPerson = new List<Person>(); private void BtnAdd_Click(object sender, RoutedEventArgs e) { string firstName = TxtFirstName.Text; string lastName = TxtLastName.Text; string fullName = TxtFirstName.Text + " " + TxtLastName.Text; string inputAge = TxtAge.Text; int age = int.Parse(inputAge); if (firstName != "" || lastName != "") { NameList.Items.Add(fullName + " : "); listOfPerson.Add(fullName + inputAge); //ここは修正が必要です。 } } private void BtnSort_Click(object sender, RoutedEventArgs e) { //ここでlistOfPersonのリストをソートしたかったのですが、OrderByを使う関係でクラスを作らねばなりませんでした。 } private void BtnDivide_Click(object sender, RoutedEventArgs e) { int nrOfCookies = int.Parse(TxtTotalCandies.Text); int c = listOfPerson.Count; int pcsPerPerson = nrOfCookies / c; int remainder = nrOfCookies % c; for (int i = 0; i < c; i++) { NameList.Items[i] += " " + " もらえるクッキーは"+(pcsPerPerson).ToString() + " 個です。"; } if (remainder != 0) { for (int i = 0; i < remainder; i++) { NameList.Items[i] += " " + "+1" + " 1個のおまけもつきます。"; } } } private void BtnClear_Click(object sender, RoutedEventArgs e) { string firstName = TxtFirstName.Text; string lastName = TxtLastName.Text; NameList.Items.Clear(); listOfPerson.Clear(); TxtFirstName.Clear(); TxtLastName.Clear(); TxtAge.Clear(); TxtTotalCookies.Clear(); } } }

試したこと

ここに問題に対して試したことを記載してください。

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

papinianus

2018/12/27 00:25

Personクラスって今どうなってます?List<Person>としているのにPersonクラスがリストの追加やソートをするというのがピンとこないので。
takabosoft

2018/12/27 02:15

ソースは```で囲ってください。
irm

2018/12/27 04:37

>papinianusさま Personクラスは、その後進展がないというか、1つのクラスとしてくくって外に出すことで元のcsとどう連動させたらいいかが謎だらけで…。List<Person>はList<T>のTをPersonとして扱っているので、PersonクラスのプロパティかフィールドかのTypeを蓄えられるはずですが、私自身もいまいち理解しきれていないです。ええと、すみません、質問はそういうことではないですか。List<Person>をOrderByでAgeでソートしたいので、クラス作成時に設定できるプロパティが必要だと思ったのですが…。クラスの勉強にもなるので、どのみちクラス化は免れません…。
irm

2018/12/27 04:55

>takabosoftさま ソースを囲いました。
guest

回答3

0

先ずは、teratailツールの使い方を覚えましょう。
![コード挿入ボタン]

コード挿入ボタンを使えば、コードの挿入タグが追加されて、貼り付けたコードのネストが正しく表示出来るようになります。
ベタに貼り付けるとコードのネストが失われて非常に見づらく、回答が敬遠されがちです。

サンプル

c#

1using System; 2using System.Collections.Generic; 3 4namespace Database 5{ 6 public class Account 7 { 8 public long No { get; set; } 9 public string Account { get; set; } 10 } 11} 12

クラスなしで書いていたプログラムです。

正しい表現ではないと思います。
C#はオブジェクト指向言語です。
従ってクラスなしではコードが記述できません。
「クラスなし」ではなく、「クラスが分割されていない」が正解だと思います。

Listは.NetFrameworkが提供するクラスです。

List<Person> listOfPerson = new List<Person>();
上記のようにnew Listと記述する事でList<Person>型変数listOfPersonにクラスインスタンスが生成されてコード上で利用できるようになるのです。

ちなみに以下のように記述しても同じ振る舞いです。
var listOfPerson = new List<Person>();
このメリットは変数に型宣言が含まれないので右辺のコードを改変するだけでリファクタリングが容易になります。デメリットとしてはルールを知らないと変数型がコードから読み取り難くなります。

Personクラスでは、リストへの追加とソートを設計
Calculatorクラスでは計算部分を設計

恐らく、プログラムを改変(リファクターリング)する事にとらわれてやるべきことを見失っているだけだと思いますので、先ずはリファクターリングするコードから離れる方が良いと思います。

上記のクラス設計が出来ているので、クラス設計に従ってクラスの骨格をコーディングする事から始めてみましょう。
例えば、以下のようにPersonクラスの骨格コードを記述しておき、リファクターリングするプログラムから
クラスメソッドを実行するコード記述してみるのがコードをリファクタリングして構造化プログラミング(クラス分割する)を理解するにあたって良いと思います。
その上でクラスメソッドが正しい結果が返却されるようにコーディングする事で正しい振る舞いを行えるようになります。

c#

1using System; 2 3namespace renshu 4{ 5 public class Person 6 { 7 public List<Person> GetPersonList() 8 { 9 //TODO List<Person>型の変数にリストメンバーを追加してインスタンスをretunするコードを記述する 10 return new List<Person>(); 11 } 12}

投稿2018/12/26 16:50

kinkin334

総合スコア62

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

irm

2018/12/27 04:26

ありがとうございます。List<T>の説明がわかりやすく助かりました。リファクタリングの呼称も初めて知りました。
guest

0

ベストアンサー

  • クラス

多分Personは名前や年齢を保持するのだと思う。個々の個人を表現するPersonクラスが、リストの追加やソートを管理するっていうのは変ではないでしょうか?

  • ソート

ソートのためにクラス化が不可避とのことですが、ListはSort()をもっているので、単にlistOfPerson.Sort()とすればソートされるはず。ただし、その際、PersonクラスがIComparableを実装している必要がありますが。

  • メイン側

csharp

1 //リストはメインに持ってればいい。リストを管理する別クラスをもってもいいかもしれないが、それってPersonとは違うはず(PersonListクラスとかになるはず) 2 private List<Person> listOfPerson = new List<Person>(); 3 private void BtnAdd_Click(object sender, RoutedEventArgs e) 4 { 5 string firstName = TxtFirstName.Text; 6 string lastName = TxtLastName.Text; 7 string fullName = TxtFirstName.Text + " " + TxtLastName.Text; 8 string inputAge = TxtAge.Text; 9 int age = int.Parse(inputAge); 10 11 if (!string.IsNullOrEmpty(firstName) || !string.IsNullOrEmpty(lastName)) 12 { 13 listOfPerson.Add(new Person(firstName, lastName, age)); //listはメインにいるので、newしてAddすればいいはず。 14 } 15 } 16 17 private void Sort() 18 { 19 listOfPerson.Sort(); //これでソートがきくはず、多分 20 }
  • 想定するクラス

(参考程度)

csharp

1public class Person : IComparable, IComparable<Person> 2{ 3 public string FirstName {get;set;} 4 public string LastName {get;set;} 5 public int Age {get;set;} 6 private Person() {} 7 public Person(string firstName, string lastName, int age) 8 { 9 FirstName = firstName; 10 LastName = lastName; 11 Age = age; 12 } 13 public int CompareTo(Person other) 14 { 15 if (other == null) 16 { 17 return 1; 18 } 19 return (this.LastName != other.LastName) ? this.LastName.CompareTo(other.LastName) : ((this.FirstName != other.FirstName) ? this.FirstName.CompareTo(other.FirstName) : this.Age.CompareTo(other.Age)); 20 } 21 22 public int CompareTo(object obj) 23 { 24 if (obj == null) 25 { 26 return 1; 27 } 28 if(!(obj is Person)) 29 { 30 throw new ArgumentException("型があいません。", "obj"); 31 } 32 return this.CompareTo(obj as Person); 33 } 34} 35public static class Calcurator 36{ 37 public static (int Quot, int Rem) Divider(int item, int person) => (item / person, item % person); 38}

投稿2018/12/27 05:19

papinianus

総合スコア12705

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

irm

2018/12/27 06:17 編集

>//リストはメインに持ってればいい。リストを管理する別クラスをもってもいいかもしれないが、それってPersonとは違うはず(PersonListクラスとかになるはず) ありがとうございます。こういった括り方のセンスがほぼゼロの状態なので、そういう風に考えればよいのですね。Personクラス内で、リストの管理までするのかと思っていました…。
papinianus

2018/12/27 06:23

それは責務の分離ができてない状態ですね。パーソンは人ですよね?学生だと考えると、学生個人が、教室の管理はしませんよね?管理しているのは学校かせめて先生です。そういうクラスが別にあるべきと考えます。
irm

2018/12/27 14:10

なるほどわかりました。UMLクラス図を考えるイメージでいけばよさそうですね。以前勉強しておいて、つながっていませんでした…。ありがとうございます。
guest

0

OrderByを使用してとあるので、LINQでの実装を考えられているのだと思います。
下記のような感じになるかと。

C#

1 public class Person 2 { 3 public string FirstName { get; set; } 4 public string LastName { get; set; } 5 public int Age { get; set; } 6 private Person() { } 7 public Person(string firstName, string lastName, int age) 8 { 9 FirstName = firstName; 10 LastName = lastName; 11 Age = age; 12 } 13 } 14 15 private List<Person> listOfPerson = new List<Person>(); 16 17 void Test() 18 { 19 listOfPerson.Add(new Person("test1", "TEST1", 15)); 20 listOfPerson.Add(new Person("test2", "TEST2", 30)); 21 listOfPerson.Add(new Person("test3", "TEST3", 10)); 22 listOfPerson.Add(new Person("test4", "TEST4", 20)); 23 listOfPerson.Add(new Person("test5", "TEST5", 45)); 24 listOfPerson.Add(new Person("test6", "TEST6", 40)); 25 26 listOfPerson = listOfPerson.OrderBy(x => x.Age).ToList<Person>(); 27 }

投稿2018/12/27 05:44

YAmaGNZ

総合スコア10258

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

irm

2018/12/27 14:06

ありがとうございます。OrderByを使えるとよいです。Test()はメインクラスのあるcsに入れてよいということでしょうか?
YAmaGNZ

2018/12/27 14:22

サンプルですので、この通り書く必要はありません。 List<Person>に対して、OrdeByはこういう風に書けばいいですって示しているだけです。 Personクラスに関してや、List<Person>の構築方法に関しては他の方の回答を参照してください。
irm

2018/12/29 15:07

こちら見落としていました。わかりました。ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問