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

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

ただいまの
回答率

90.34%

  • C#

    7673questions

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

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

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 166

cutedog

score 122

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

//クラスです。長すぎるので一部抜粋です。

    [Serializable]

    class EigyoGyoumuDto
    {
        /// <summary>
        /// 共通ロジック
        /// </summary>
        public CommonLogic cmnLc;

        /// <summary>
        /// 担当者マスタ辞書
        /// </summary>
        public IDictionary<int?, MTantouDto> _MTantouDic { set; get; }

        /// <summary>
        /// 得意先マスタ辞書
        /// </summary>
        public IDictionary<String, MTokuisakiDto> _MTokuisakiDic { set; get; }

        /// <summary>
        /// 見積りヘッダ
        /// </summary>
        public TMitsumoriHeadDto _TMitsumoriHeadDto { set; get; }

        /// <summary>
        /// 見積りヘッダ属性
        /// </summary>
        public TMitsumoriHeadZokuseiDto _TMitsumoriHeadZokuseiDto { set; get; }

        /// <summary>
        /// 見積り明細
        /// </summary>
        public TMitsumoriDetailDto _TMitsumoriDetailDto { set; get; }

        /// <summary>
        /// 見積り明細属性
        /// </summary>
        public TMitsumoriDetailZokuseiDto _TMitsumoriDetailZokuseiDto { set; get; }

        /// <summary>
        /// 受注属性
        /// </summary>
        public TJuchuZokuseiDto _TJuchuZokuseiDto { set; get; }

        /// <summary>
        /// 変換前ファイル名
        /// </summary>
        public String BeforeConversionFileName { set; get; }

        /// <summary>
        /// 変換前ファイルパス名
        /// </summary>
        public String BeforeConversionFilePath { set; get; }



        /// <summary>
        /// 変換後ファイル名
        /// </summary>
        public String AfterConversionFileName
        {
            get
            {
                if (String.IsNullOrEmpty(BeforeConversionFileName) && _TMitsumoriDetailZokuseiDto == null)
                {
                    return String.Empty;
                }

                String MitFileNm = String.Empty;
                //コンボボックスを選択している場合
                if (!String.IsNullOrEmpty(BeforeConversionFileName))
                {
                    //変換前ファイル名の拡張子を取得
                    String Extension = Path.GetExtension(BeforeConversionFileName);
                    MitFileNm = MitCode + "-" + GenericUtil.ZeroPadding(GenericUtil.StringTryparse2(_TMitsumoriDetailDto.MitSeq), 2) + Extension;

                    //既存のファイル名取得
                    if (_TMitsumoriDetailZokuseiDto == null)
                    {
                        TMitsumoriDetailZokuseiDtoNewInstance();

                    }
                    _TMitsumoriDetailZokuseiDto.MitFileNm = MitFileNm;

                }


                return _TMitsumoriDetailZokuseiDto.MitFileNm;

            }

        }

        /// <summary>
        /// 計算書発行日(属性情報)
        /// </summary>
        public DateTime? MitDate
        {
            set
            {
                if (_TMitsumoriHeadZokuseiDto == null)
                {
                    TMitsumoriHeadZokuseiDtoNewInstance();
                }

                _TMitsumoriHeadZokuseiDto.MitDate = value;

            }
            get
            {
                if (_TMitsumoriHeadZokuseiDto == null)
                {
                    return null;
                }
                return _TMitsumoriHeadZokuseiDto.MitDate;
            }

        }

        /// <summary>
        /// 御見積書発行日(属性情報)
        /// </summary>
        public DateTime? MitMitsumorishoDate
        {
            set
            {
                if (_TMitsumoriHeadZokuseiDto == null)
                {
                    TMitsumoriHeadZokuseiDtoNewInstance();
                }

                _TMitsumoriHeadZokuseiDto.MitMitsumorishoDate = value;

            }
            get
            {
                if (_TMitsumoriHeadZokuseiDto == null)
                {
                    return null;
                }
                return _TMitsumoriHeadZokuseiDto.MitMitsumorishoDate;
            }

        }


        /// <summary>
        /// 備考3
        /// </summary>
        public String MitEigyoBikou3
        {

            set
            {
                TMitsumoriDetailZokuseiDtoNewInstance();

                _TMitsumoriDetailZokuseiDto.MitEigyoBikou3 = value;
            }

            get
            {
                if (_TMitsumoriDetailZokuseiDto == null)
                {
                    return String.Empty;
                }

                return _TMitsumoriDetailZokuseiDto.MitEigyoBikou3;


            }

        }
    }        







                    //2件目以降のデータが1件目と同じかチェックする場合
                    if (ChkDataSameCheck.Checked)
                    {

                        IList<EigyoGyoumuDto> _EigyoGyoumuDtoList = new List<EigyoGyoumuDto>();
                        _EigyoGyoumuDtoList = DataList;
                        //比較用に1件目を退避しておく
                        ZokuseiDto First_ZokuseiDto = _EigyoGyoumuDtoList[0]._ZokuseiDto;
                        PropertyInfo[] infoArrayOfFirst = First_ZokuseiDto.GetType().GetProperties();

                        foreach (EigyoGyoumuDto dto in _EigyoGyoumuDtoList)
                        {

                            if (dto._ZokuseiDto != null)
                            {

                                PropertyInfo[] infoArray = dto._ZokuseiDto.GetType().GetProperties();
                                int idx = 0;
                                // プロパティ情報出力をループで回す
                                foreach (PropertyInfo infoFirst in infoArrayOfFirst)
                                {

                                    MethodInfo getAccessor = infoFirst.GetMethod;

                                    Object first = infoFirst.GetValue(First_ZokuseiDto);
                                    Object data = infoArray[idx].GetValue(dto._ZokuseiDto);
                                    if (first == null || data == null)
                                    {

                                        if ((first != null && data == null) || (first == null && data != null))
                                        {
                                            Message_Warn("2件目以降のデータが1件目と違います。");
                                            return;
                                        }

                                    }
                                    else
                                    {
                                        if (!first.Equals(data))
                                        {
                                            Message_Warn("2件目以降のデータが1件目と違います。");
                                            return;
                                        }
                                    }

                                    idx++;
                                }

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

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

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

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

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

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

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

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

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • papinianus

    2018/07/05 19:48 編集

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

    キャンセル

  • cutedog

    2018/07/05 20:34

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

    キャンセル

回答 2

checkベストアンサー

+1

別の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/06 11: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
    }

    キャンセル

  • 2018/07/06 12:28

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

    キャンセル

  • 2018/07/06 12:40 編集

    GetHashCodeですが、Distinct()などで使っているので、Equalsと同様の結果となるように実装しないと正しい結果となりません。

    また、IEquatableだけではなく、Equals(object)のオーバーロードも必要かと思います。
    List<Person>のContainsを使用する場合などはEquatable<Person>.Equalsが使用されますが、
    Person.Equalsの場合はEquals(object)が使用されるので、結果が違ってきます。
    また、==、!=演算子との結果も異なってきますので、こちらも実装したほうがよいかと思います。

    どのような使用のしかたをするかによって、最低限どのメソッドを実装するかは変わってくると思いますので考えてみてください。

    キャンセル

  • 2018/07/06 12:51

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

    キャンセル

+1

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

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

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/06 10:51

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

    キャンセル

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

  • C#

    7673questions

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

  • トップ
  • C#に関する質問
  • 同じオブジェクトの1件目と2件目以降の各プロパティの値が同じかどうかを比較をしたい。