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

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

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

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

Q&A

解決済

2回答

1306閲覧

同じオブジェクトの1件目と2件目以降の各プロパティの値が同じかどうかを比較をしたい。

cutedog

総合スコア177

C#

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

0グッド

0クリップ

投稿2018/07/05 10:11

編集2018/07/05 11:43

お世話になります。
標記のとおり、同じオブジェクト(_ZokuseiDto )の1件目と2件目以降の各プロパティの値が同じかどうかを比較をしたいのですが、これを実行するとオブジェクト(_ZokuseiDto )の中で定義している別のIList型のオブジェクトのプロパティのCount?のところで値が相違してしまいます。
どう対処すればよいのか見当がつきません。
どなたかご教授おねがいします。

C#

1//クラスです。長すぎるので一部抜粋です。 2 3 [Serializable] 4 5 class EigyoGyoumuDto 6 { 7 /// <summary> 8 /// 共通ロジック 9 /// </summary> 10 public CommonLogic cmnLc; 11 12 /// <summary> 13 /// 担当者マスタ辞書 14 /// </summary> 15 public IDictionary<int?, MTantouDto> _MTantouDic { set; get; } 16 17 /// <summary> 18 /// 得意先マスタ辞書 19 /// </summary> 20 public IDictionary<String, MTokuisakiDto> _MTokuisakiDic { set; get; } 21 22 /// <summary> 23 /// 見積りヘッダ 24 /// </summary> 25 public TMitsumoriHeadDto _TMitsumoriHeadDto { set; get; } 26 27 /// <summary> 28 /// 見積りヘッダ属性 29 /// </summary> 30 public TMitsumoriHeadZokuseiDto _TMitsumoriHeadZokuseiDto { set; get; } 31 32 /// <summary> 33 /// 見積り明細 34 /// </summary> 35 public TMitsumoriDetailDto _TMitsumoriDetailDto { set; get; } 36 37 /// <summary> 38 /// 見積り明細属性 39 /// </summary> 40 public TMitsumoriDetailZokuseiDto _TMitsumoriDetailZokuseiDto { set; get; } 41 42 /// <summary> 43 /// 受注属性 44 /// </summary> 45 public TJuchuZokuseiDto _TJuchuZokuseiDto { set; get; } 46 47 /// <summary> 48 /// 変換前ファイル名 49 /// </summary> 50 public String BeforeConversionFileName { set; get; } 51 52 /// <summary> 53 /// 変換前ファイルパス名 54 /// </summary> 55 public String BeforeConversionFilePath { set; get; } 56 57 58 59 /// <summary> 60 /// 変換後ファイル名 61 /// </summary> 62 public String AfterConversionFileName 63 { 64 get 65 { 66 if (String.IsNullOrEmpty(BeforeConversionFileName) && _TMitsumoriDetailZokuseiDto == null) 67 { 68 return String.Empty; 69 } 70 71 String MitFileNm = String.Empty; 72 //コンボボックスを選択している場合 73 if (!String.IsNullOrEmpty(BeforeConversionFileName)) 74 { 75 //変換前ファイル名の拡張子を取得 76 String Extension = Path.GetExtension(BeforeConversionFileName); 77 MitFileNm = MitCode + "-" + GenericUtil.ZeroPadding(GenericUtil.StringTryparse2(_TMitsumoriDetailDto.MitSeq), 2) + Extension; 78 79 //既存のファイル名取得 80 if (_TMitsumoriDetailZokuseiDto == null) 81 { 82 TMitsumoriDetailZokuseiDtoNewInstance(); 83 84 } 85 _TMitsumoriDetailZokuseiDto.MitFileNm = MitFileNm; 86 87 } 88 89 90 return _TMitsumoriDetailZokuseiDto.MitFileNm; 91 92 } 93 94 } 95 96 /// <summary> 97 /// 計算書発行日(属性情報) 98 /// </summary> 99 public DateTime? MitDate 100 { 101 set 102 { 103 if (_TMitsumoriHeadZokuseiDto == null) 104 { 105 TMitsumoriHeadZokuseiDtoNewInstance(); 106 } 107 108 _TMitsumoriHeadZokuseiDto.MitDate = value; 109 110 } 111 get 112 { 113 if (_TMitsumoriHeadZokuseiDto == null) 114 { 115 return null; 116 } 117 return _TMitsumoriHeadZokuseiDto.MitDate; 118 } 119 120 } 121 122 /// <summary> 123 /// 御見積書発行日(属性情報) 124 /// </summary> 125 public DateTime? MitMitsumorishoDate 126 { 127 set 128 { 129 if (_TMitsumoriHeadZokuseiDto == null) 130 { 131 TMitsumoriHeadZokuseiDtoNewInstance(); 132 } 133 134 _TMitsumoriHeadZokuseiDto.MitMitsumorishoDate = value; 135 136 } 137 get 138 { 139 if (_TMitsumoriHeadZokuseiDto == null) 140 { 141 return null; 142 } 143 return _TMitsumoriHeadZokuseiDto.MitMitsumorishoDate; 144 } 145 146 } 147 148 149 /// <summary> 150 /// 備考3 151 /// </summary> 152 public String MitEigyoBikou3 153 { 154 155 set 156 { 157 TMitsumoriDetailZokuseiDtoNewInstance(); 158 159 _TMitsumoriDetailZokuseiDto.MitEigyoBikou3 = value; 160 } 161 162 get 163 { 164 if (_TMitsumoriDetailZokuseiDto == null) 165 { 166 return String.Empty; 167 } 168 169 return _TMitsumoriDetailZokuseiDto.MitEigyoBikou3; 170 171 172 } 173 174 } 175 } 176 177 178 179 180 181 182 183 //2件目以降のデータが1件目と同じかチェックする場合 184 if (ChkDataSameCheck.Checked) 185 { 186 187 IList<EigyoGyoumuDto> _EigyoGyoumuDtoList = new List<EigyoGyoumuDto>(); 188 _EigyoGyoumuDtoList = DataList; 189 //比較用に1件目を退避しておく 190 ZokuseiDto First_ZokuseiDto = _EigyoGyoumuDtoList[0]._ZokuseiDto; 191 PropertyInfo[] infoArrayOfFirst = First_ZokuseiDto.GetType().GetProperties(); 192 193 foreach (EigyoGyoumuDto dto in _EigyoGyoumuDtoList) 194 { 195 196 if (dto._ZokuseiDto != null) 197 { 198 199 PropertyInfo[] infoArray = dto._ZokuseiDto.GetType().GetProperties(); 200 int idx = 0; 201 // プロパティ情報出力をループで回す 202 foreach (PropertyInfo infoFirst in infoArrayOfFirst) 203 { 204 205 MethodInfo getAccessor = infoFirst.GetMethod; 206 207 Object first = infoFirst.GetValue(First_ZokuseiDto); 208 Object data = infoArray[idx].GetValue(dto._ZokuseiDto); 209 if (first == null || data == null) 210 { 211 212 if ((first != null && data == null) || (first == null && data != null)) 213 { 214 Message_Warn("2件目以降のデータが1件目と違います。"); 215 return; 216 } 217 218 } 219 else 220 { 221 if (!first.Equals(data)) 222 { 223 Message_Warn("2件目以降のデータが1件目と違います。"); 224 return; 225 } 226 } 227 228 idx++; 229 } 230 231 } 232 } 233 }

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

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

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

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

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

papinianus

2018/07/05 11:02 編集

EigyoGyoumuDtoのクラス構造は未知というか、自作ではないという前提なのですか?(もしかしてクラス構造が変わっても対応できるようにしようとしている?)
cutedog

2018/07/05 11:34

EigyoGyoumuDtoのクラス構造は自作です。画面の一覧のDatasourceに食わせるためのクラスなので、内容としては、DBから取得したIList型のオブジェクトが数個と、それらから切り出した項目のGetやSetが含まれます。将来的にプロパティが増える可能性はあります。比較したいのは、切り出した項目のプロパティです。
guest

回答2

0

ベストアンサー

別のIList型のオブジェクトのプロパティのCount?のところで値が相違してしまいます。

これはおそらく参照型(値型との対比)であるために、ReferenceEqualで等値判断がなされて一致しないことになるのだと思われます。
なので例えばGetValueしたfirstなどをIList<T>にキャストするなどして、nullでなかったらSequenceEqualで判定する、とか、型がIListを実装しているか判定するというような処理を書けば判断はできると思いますが、やめたほうがいいです。

YAmaGNZさんと似た話になるのですが、IEquatableを実装して(つまりEquals/GetHashcodeを実装して)EigyoGyoumuDtoクラス自身を"等値比較可能"な型にするほうがいいです。
それはEigyoGyoumuDtoクラスの責務です。EigyoGyoumuDtoが同じかどうかの判断をそのクラス外でするのはおかしいと思います。
また、TMitsumoriDetailDtoのようなものも内部に含んでおり、これらもプロパティをとって単に==で比較することはできません。つまり、IListであるかの判定以外にも特定のクラスであるかの判定を繰り返さないといけなくなります。Dtoクラスを拡張して、参照型以外のプロパティが増えればifの分岐がどんどん増えることになり、到底メンテできないと思います(等値判断が将来的にここだけでしかやらないというのでしょうか?)

また、IEquatableを実装しておけば、Distinct()が使えるので、Count()とDistinct().Count()を比べるだけで、重複があるかを判定できることになります。

今一度設計から見直すことをおすすめします。

蛇足ですが、objectで比較するコードが出てくるのでは、何のために静的型言語を使っているのかわからなくなります。objectが出てきた時点でまずいコードを書いていると考えたほうがいいと思います。

投稿2018/07/05 12:42

papinianus

総合スコア12705

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

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

cutedog

2018/07/06 02:07

ありがうございます。 下記のようなサンプル見つけたのですが、こういうふうに書いた方がいいということですかね? しかし、IEquatableの実装内容の意味はわかるのですが、 GetHashCode()の実装を何故しないといけないのかがわからない・・・ でも下記のサンプルのようにすればいいのですかね? public class Person : IEquatable<Person> { private string name; private DateTime birthday; public string Name { get { return name; } } public DateTime Birthday { get { return birthday; } } public Person(string name, DateTime birthday) { this.name = name; this.birthday = birthday; } // 実装するのを忘れやすいので注意 public override int GetHashCode() { return name.GetHashCode() ^ birthday.GetHashCode(); } #region IEquatable<Person> メンバ bool IEquatable<Person>.Equals(Person other) { if (other == null) { return false; } return name == other.name && birthday == other.birthday; } #endregion }
papinianus

2018/07/06 03:28

そうですね、こういう感じだと思います。クラス自身が同じかの決め方をルール付けしたほうがいいので。 今回のだと、見積とかもIEquatableを実装しとかないと上手く比較できないかもしれないです。 Hash値は名前のとおり、HashSetで同一判定したり、あるいはDictionaryのキーになったときに使われたりします(のはずです)。簡易、高速に同一かを判定するときに使います。なので、違うとみなすものは、違うHash値になるようにしてください。
YAmaGNZ

2018/07/06 03:41 編集

GetHashCodeですが、Distinct()などで使っているので、Equalsと同様の結果となるように実装しないと正しい結果となりません。 また、IEquatableだけではなく、Equals(object)のオーバーロードも必要かと思います。 List<Person>のContainsを使用する場合などはEquatable<Person>.Equalsが使用されますが、 Person.Equalsの場合はEquals(object)が使用されるので、結果が違ってきます。 また、==、!=演算子との結果も異なってきますので、こちらも実装したほうがよいかと思います。 どのような使用のしかたをするかによって、最低限どのメソッドを実装するかは変わってくると思いますので考えてみてください。
cutedog

2018/07/06 03:51

了解です。 元が独学の老年コボラーなので理解に時間が掛かりそうですが 試行錯誤してみます。 ありがとうございました。。
guest

0

状況を正確に把握できていませんが、
公開しているプロパティ全てを比較したいのではなく、一部のプロパティのみを比較したいというのであれば
==、!=演算子(Equals、GetHashCodeも)をオーバーロードするのがいいのではないかと思います。

そうでないなら、読み飛ばしてください。

投稿2018/07/05 12:12

YAmaGNZ

総合スコア10242

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

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

cutedog

2018/07/06 01:51

参考になりました。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問