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

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

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

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

Q&A

解決済

4回答

1824閲覧

C#でthisとforeachの組み合わせで悩んでいます。

picko

総合スコア52

C#

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

0グッド

2クリップ

投稿2016/07/20 01:44

編集2016/07/20 02:28

こんにちは。
C#でthisとforeachの組み合わせで悩んでいます。
Windows10, VisualStudio2015です。

multi windowのprogramを作っていて、windowのtop, left, width, heightをすべて保存しようというのです。
困っているのはEqualsの実装です。

C#

1using System.Windows; 2 3namespace multiwindows 4{ 5 public class WindowProperty 6 { 7 public double Top { get; set; } 8 public double Left { get; set; } 9 public double Width { get; set; } 10 public double Height { get; set; } 11 } 12}

として。

C#

1namespace multiwindow 2{ 3 using System.Collections.Generic; 4 5 public class UserSetting 6 { 7 public WindowProperty MainWindowProperty { get; set; } 8 public WindowProperty SettingWindowProperty { get; set; } 9 public WindowProperty ToolWindowProperty { get; set; } 10 public WindowProperty AllMapWindowProperty { get; set; } 11 public WindowProperty StatusWindowProperty { get; set; } 12 13 public override int GetHashCode() 14 { 15 return 1; 16 } 17 18 public override bool Equals(object obj) 19 { 20 if (this == obj) return true; 21 if (obj == null) return false; 22 if (this.GetType() != obj.GetType()) 23 return false; 24 25 var other = (UserSetting)obj; 26 if (this.MainWindowProperty != other.MainWindowProperty) return false; 27 if (this.SettingWindowProperty != other.SettingWindowProperty) return false; 28 if (this.ToolWindowProperty != other.ToolWindowProperty) return false; 29 if (this.AllMapWindowProperty != other.AllMapWindowProperty) return false; 30 if (this.StatusWindowProperty != other.StatusWindowProperty) return false; 31 32 return true; 33 } 34 } 35} 36 37

という最後の部分、むちゃくちゃ繰り返しで保守性悪そうじゃないですか。
で、

C#

1List<WindowProperty> properties = new List<WindowProperty>(); 2properties.Add(MainWindowProperty); 3properties.Add(SettingWindowProperty); 4properties.Add(ToolWindowProperty); 5properties.Add(AllMapWindowProperty); 6properties.Add(StatusWindowProperty); 7 8foreach (var property in properties) 9 if (this.property != other.property) 10 return false; 11

としたら楽かもと考えたのです。
ところが、
other.propertyでUserSettingにpropertyがないとエラー。
こういうときって、どうすればよいのでしょう?

List<WindowProperty> properties = new List<WindowProperty>();
をfieldにして、さらにfieldに
public WindowProperty property { get; set; }
を追加するとコード上のエラーはなくなりますが、this.propertyとother.propertyではなくて、propertiesに追加したものをforでくるくる回したいです。
アドバイスお願いします。

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

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

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

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

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

guest

回答4

0

私なら、このようにPropertiesを実装します。

C#

1public IEnumurator<WindowProperty> Properties {get 2 { 3 yield return This.MainWindowProperty; 4 yield return This.SettingWindowProperty; 5 yield return This.ToolWindowProperty; 6 yield return This.AllMapWindowProperty; 7 yield return This.StatusWindowProperty; 8 } 9}

理由は、
・Listに入れる方法もありますが、私はgetterを書かずにいられない。
・外部から変数をいじられたくない。
といったことです。

Equalsにしか使わないメソッドなので、publicというのはあまりよくないかなともおもいますが・・・


おそかったですね。

投稿2016/07/20 05:03

編集2016/07/20 05:06
iwamoto_takaaki

総合スコア2883

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

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

picko

2016/07/20 05:05

ありがとうございます。 yieldはまだ使ったことがないですが、勉強になります。
picko

2016/07/20 05:15

いえいえ。またよろしくお願いします。
guest

0

ベストアンサー

ベタに書くと、下のようになるでしょう。

List<WindowProperty> thisProperties = new List<WindowProperty>(); thisProperties.Add(this.MainWindowProperty); thisProperties.Add(this.SettingWindowProperty); thisProperties.Add(this.ToolWindowProperty); thisProperties.Add(this.AllMapWindowProperty); thisProperties.Add(this.StatusWindowProperty); List<WindowProperty> otherProperties = new List<WindowProperty>(); otherProperties.Add(other.MainWindowProperty); otherProperties.Add(other.SettingWindowProperty); otherProperties.Add(other.ToolWindowProperty); otherProperties.Add(other.AllMapWindowProperty); otherProperties.Add(other.StatusWindowProperty); for (int i = 0; i < thisProperties.Count; i++) { if (thisProperties[i] != otherProperties[i]) return false; }

さらにコードをまとめていくと ozwk さんの回答になると思います。

また、 ==SequenceEqual も、このままでは「参照の等価」を評価してしまうので、 WindowProperty を class でなく struct にするか、WindowPropertyEquals メソッドを override する必要があると思います。

投稿2016/07/20 03:57

amay077

総合スコア1075

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

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

picko

2016/07/20 04:07

なるほど。ありがとうございます。
picko

2016/07/20 04:18

WindowPropertyにもEqualsメソッドをoverrideしました。 アドバイス感謝です。
guest

0

何がしたいんだかよくわからないんですが
多分こういうことですかね?

C#

1public class UserSetting 2{ 3 public List<WindowProperty> Properties { get; } 4 5 6 public override int GetHashCode() 7 { 8 return 1; // (この実装はどうなのかとは思う) 9 } 10 11 public override bool Equals(object obj) 12 { 13 if (this == obj) return true; 14 if (obj == null) return false; 15 if (this.GetType() != obj.GetType()) 16 return false; 17 18 var other = (UserSetting)obj; 19 return this.Equals(other); 20 } 21 22 public bool Equals(UserSetting other) 23 { 24 return this.Properties.SequenceEqual(other.Properties); 25 } 26} 27

投稿2016/07/20 02:28

ozwk

総合スコア13521

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

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

picko

2016/07/20 04:12

return 1はわたしもどうかと思いますがとりあえずそうなっているので措きます。 thisとotherでまるごと比較でOKなのでしょうか? List<WindowProperties>の登録は必要ですか?
ozwk

2016/07/20 04:20

MainWindowPropertyやら SettingWindowPropertyやらを用意する代わりに Propertiesを用意しています。 いやいやそうじゃなくてListはあくまでローカルで使いたいんだよって場合は amay077さんのようにローカルで用意してそれぞれaddしてください。
picko

2016/07/20 05:03

あーそういうことですね。理解しました。 とすると、どのWindowのpropertyを保存したかを情報としてもつ必要がありますね。 こちらのほうがsmartですが、今回の要求では、WindowPropertyを改良することは不可っぽいので、best answerはamay077さんに。
guest

0

if (this.property != property) return false; じゃないですか?
###追記
properties が使えるとして、

C#

1properties.SequentialEqual(other.properties)

で比較できると思います。

ただ、properties はプライベートフィールドなので、あまりこのような使い方を多用すると保守性が悪くなります。ローカル変数ならそもそも使えません。パブリックプロパティなどに昇格できるか検討してみてください。

投稿2016/07/20 01:54

編集2016/07/20 02:45
Zuishin

総合スコア28660

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

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

picko

2016/07/20 02:04

それだと、propertyにMainWindowProperty(etc.)は入りますが、this.propertyは固定なのではないかなと。
Zuishin

2016/07/20 02:09

もちろん固定です。foreach を使う前のソースでも固定で、同じ処理になると思いますが、これを変えるのですか? てっきり同じ処理を繰り返しを使って置き換えたいという質問だと思っていましたが、真意は何でしょうか? それと、ソースが非常にみにくいので、インデントをつけてください。 これだと無用なバグが入ります。
picko

2016/07/20 02:29

if (this.MainWindowProperty != other.MainWindowProperty) return false; if (this.SettingWindowProperty != other.SettingWindowProperty) return false; if (this.ToolWindowProperty != other.ToolWindowProperty) return false; if (this.AllMapWindowProperty != other.AllMapWindowProperty) return false; if (this.StatusWindowProperty != other.StatusWindowProperty) return false; をforeachしたいのです。
Zuishin

2016/07/20 02:47

パブリックプロパティなどと書きましたが、私ならインターナルプロパティにすると思います。
Zuishin

2016/07/20 02:48

と書いたら ozwk さんに先に書かれていました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問