দুটি জটিল বস্তুর তুলনা করার সর্বোত্তম উপায়


112

আমি দুই জটিল বস্তু আছে Object1এবং Object2। তাদের কাছে প্রায় 5 স্তরের শিশু অবজেক্ট রয়েছে।

সেগুলি একই কি না তা বলার জন্য আমার দ্রুততম পদ্ধতি প্রয়োজন।

এটি সি # 4.0 এ কীভাবে করা যায়?

উত্তর:


101

বাস্তবায়ন IEquatable<T>(অগ্রাহ্য উত্তরাধিকারসূত্রে সাথে সাধারণত Object.Equalsএবং Object.GetHashCodeআপনার সমস্ত কাস্টম ধরনের পদ্ধতি)। সম্মিলিত প্রকারের ক্ষেত্রে অন্তর্ভুক্ত প্রকারের মধ্যে অন্তর্ভুক্ত প্রকারের Equalsপদ্ধতিটি আহ্বান করুন । অন্তর্ভুক্ত সংগ্রহের জন্য, SequenceEqualএক্সটেনশন পদ্ধতিটি ব্যবহার করুন , যা অভ্যন্তরীণভাবে IEquatable<T>.Equalsবা Object.Equalsপ্রতিটি উপাদানকে কল করে। এই পদ্ধতির স্পষ্টতই আপনাকে আপনার ধরণের সংজ্ঞাগুলি প্রসারিত করতে হবে তবে এর ফলাফলগুলি সিরিয়ালকরণের সাথে জড়িত যে কোনও জেনেরিক সমাধানের চেয়ে দ্রুত।

সম্পাদনা করুন : নীচে বাসা বাঁধানোর তিনটি স্তর সহ এখানে একটি স্বতন্ত্র উদাহরণ।

মান ধরণের জন্য, আপনি সাধারণত তাদের Equalsপদ্ধতিটি কল করতে পারেন । এমনকি ক্ষেত্র বা বৈশিষ্ট্যগুলি কখনই স্পষ্টভাবে বরাদ্দ না করা থাকলেও তাদের ডিফল্ট মান থাকতে পারে।

রেফারেন্স ধরণের জন্য, আপনাকে প্রথমে কল করা উচিত ReferenceEquals, যা রেফারেন্সের সমতার জন্য পরীক্ষা করে - এটি যখন আপনি একই অবজেক্টটি উল্লেখ করছেন তখন এটি দক্ষতা বৃদ্ধির কাজ করবে। এটি উভয় উল্লেখ বাতিল হয়ে যায় এমন ক্ষেত্রেও পরিচালনা করবে। যদি সেই চেকটি ব্যর্থ হয় তবে নিশ্চিত করুন যে আপনার উদাহরণের ক্ষেত্র বা সম্পত্তি নাল নয় (এড়াতে NullReferenceException) এবং এর Equalsপদ্ধতিটি কল করুন । যেহেতু আমাদের সদস্যরা যথাযথভাবে টাইপ করা হয়েছে, IEquatable<T>.Equalsওভাররাইড Object.Equalsপদ্ধতিটি (যাঁর প্রয়োগের প্রকারের ফলে প্রান্তিকভাবে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে ধীরে বৃদ্ধি পাবে)

আপনি যখন ওভাররাইড করবেন তখন আপনারও ওভাররাইড হওয়া Object.Equalsআশা করা যায় Object.GetHashCode; সংক্ষিপ্ততার জন্য আমি নীচে এটি করিনি।

public class Person : IEquatable<Person>
{
    public int Age { get; set; }
    public string FirstName { get; set; }
    public Address Address { get; set; }

    public override bool Equals(object obj)
    {
        return this.Equals(obj as Person);
    }

    public bool Equals(Person other)
    {
        if (other == null)
            return false;

        return this.Age.Equals(other.Age) &&
            (
                object.ReferenceEquals(this.FirstName, other.FirstName) ||
                this.FirstName != null &&
                this.FirstName.Equals(other.FirstName)
            ) &&
            (
                object.ReferenceEquals(this.Address, other.Address) ||
                this.Address != null &&
                this.Address.Equals(other.Address)
            );
    }
}

public class Address : IEquatable<Address>
{
    public int HouseNo { get; set; }
    public string Street { get; set; }
    public City City { get; set; }

    public override bool Equals(object obj)
    {
        return this.Equals(obj as Address);
    }

    public bool Equals(Address other)
    {
        if (other == null)
            return false;

        return this.HouseNo.Equals(other.HouseNo) &&
            (
                object.ReferenceEquals(this.Street, other.Street) ||
                this.Street != null &&
                this.Street.Equals(other.Street)
            ) &&
            (
                object.ReferenceEquals(this.City, other.City) ||
                this.City != null &&
                this.City.Equals(other.City)
            );
    }
}

public class City : IEquatable<City>
{
    public string Name { get; set; }

    public override bool Equals(object obj)
    {
        return this.Equals(obj as City);
    }

    public bool Equals(City other)
    {
        if (other == null)
            return false;

        return
            object.ReferenceEquals(this.Name, other.Name) ||
            this.Name != null &&
            this.Name.Equals(other.Name);
    }
}

আপডেট : এই উত্তরটি বেশ কয়েক বছর আগে লেখা হয়েছিল। তার পর থেকে, আমি এই IEquality<T>জাতীয় দৃশ্যের জন্য পরিবর্তনীয় ধরণের জন্য প্রয়োগ থেকে দূরে ঝুঁকতে শুরু করেছি । সমতা দুটি ধারণা আছে: পরিচয় এবং সমতা । একটি স্মৃতি প্রতিনিধিত্ব স্তরে, এগুলিকে "রেফারেন্স সমতা" এবং "মান সমতা" ( সমতা তুলনা দেখুন ) হিসাবে জনপ্রিয় হিসাবে চিহ্নিত করা হয় । তবে একই পার্থক্যটি একটি ডোমেন স্তরেও প্রয়োগ করতে পারে। মনে করুন যে আপনার Personশ্রেণীর একটি PersonIdসম্পত্তি রয়েছে, স্বতন্ত্র বাস্তব-ব্যক্তির প্রতি অনন্য। একই PersonIdতবে পৃথক Ageমান সহ দুটি বস্তুকে সমান বা পৃথক বিবেচনা করা উচিত? উপরের উত্তরটি ধরে নিয়েছে যে একটি সমতার পরে। তবে এর অনেকগুলি ব্যবহার রয়েছেIEquality<T>ইন্টারফেস, যেমন সংগ্রহ যেমন, ধরে নেওয়া হয় যে এই জাতীয় বাস্তবায়ন পরিচয়ের জন্য সরবরাহ করে । উদাহরণস্বরূপ, আপনি যদি জনগোষ্ঠী স্থাপন করছেন HashSet<T>, আপনি সাধারণত TryGetValue(T,T)কলটি এমন বিদ্যমান উপাদানগুলি ফিরিয়ে আনার প্রত্যাশা করবেন যা কেবলমাত্র আপনার যুক্তির পরিচয় ভাগ করে নেবে, অগত্যা প্রয়োজনীয় উপাদানগুলির সমপরিমাণ একই নয় contents এই ধারণাটি নোটগুলি দ্বারা প্রয়োগ করা হয় GetHashCode:

সাধারণত, পরিবর্তনীয় রেফারেন্স প্রকারের জন্য, আপনার GetHashCode()কেবলমাত্র ওভাররাইড করা উচিত যদি:

  • আপনি এমন ক্ষেত্রগুলি থেকে হ্যাশ কোডটি গণনা করতে পারবেন যা পরিবর্তনীয় নয়; অথবা
  • আপনি নিশ্চিত করতে পারেন যে কোনও হ'ল কোডের উপর নির্ভর করে এমন কোনও সংস্থায় বস্তুটি থাকা অবস্থায় কোনও মিউটয়েবল অবজেক্টের হ্যাশ কোডটি পরিবর্তন হয় না।

আমি এই বিষয়টিকে আরআইএ পরিষেবাদিগুলির মাধ্যমে পেয়েছি ... আমি কি সেই আইটেমগুলির জন্য আইকোয়াটেবল <Foo> ব্যবহার করতে পারি এবং এটি ডাব্লুপিএফ ক্লায়েন্টের অধীনে পেতে পারি?
— বিকাশকারী

1
আপনার মানে ক্লাসগুলি স্বয়ংক্রিয়ভাবে উত্পন্ন? আমি আরআইএ পরিষেবাদি ব্যবহার করি নি, তবে আমি ধরে নেব যে কোনও উত্পন্ন শ্রেণি হিসাবে ঘোষণা করা হবে partial- হ্যাঁ, আপনি নিজের Equalsপদ্ধতিতে যুক্ত আংশিক শ্রেণির ঘোষণার মাধ্যমে তাদের পদ্ধতিটি প্রয়োগ করতে পারেন যা স্বয়ংক্রিয়ভাবে উত্পন্ন উত্পন্ন ক্ষেত্র / বৈশিষ্ট্যগুলি উল্লেখ করে এক.
— ডগলাস

যদি "ঠিকানা ঠিকানা" আসলে "ঠিকানা [] ঠিকানা" হয় তবে কীভাবে এটি প্রয়োগ করা হবে?
— গিওমি

2
আপনি LINQ পেরেছিলাম Enumerable.SequenceEqualঅ্যারে তে পদ্ধতি: this.Addresses.SequenceEqual(other.Addresses)। শ্রেণিটি ইন্টারফেস প্রয়োগ করে Address.Equals, এটি প্রতিটি জোড়টিকে সম্পর্কিত ঠিকানাগুলির জন্য অভ্যন্তরীণভাবে কল করবে call AddressIEquatable<Address>
— ডগলাস

2
একটি বিকাশকারী সম্ভবত তুলনা করার আরও একটি বিভাগ হ'ল "ওয়ার্কস লাইক"। আমার জন্য, এর অর্থ এই যে দুটি দৃষ্টান্তের কিছু অসম সম্পত্তি মূল্য থাকতে পারে, দুটি প্রোগ্রামের প্রক্রিয়া থেকে প্রোগ্রামটি একই ফলাফল তৈরি করবে।
— জন কার্টজ

95

উভয় অবজেক্টকে সিরিয়াল করুন এবং ফলাফলযুক্ত স্ট্রিংগুলি তুলনা করুন


1
কেন হবে তা আমি দেখছি না। ক্রমিকায়ন সাধারণত একটি অপ্টিমাইজড প্রক্রিয়া এবং আপনার যে কোনও ক্ষেত্রে প্রতিটি সম্পত্তির মান অ্যাক্সেস করতে হবে।
— জোয়েলফ্যান

5
একটি বিশাল ব্যয় আছে। আপনি একটি ডেটা স্ট্রিম তৈরি করছেন, স্ট্রিং সংযোজন করছেন এবং তারপরে স্ট্রিংয়ের সাম্যতা পরীক্ষা করছেন। মাত্রার অর্ডার, ঠিক তার মধ্যে। সিরিয়ালাইজেশন উল্লেখ না করে ডিফল্ট দ্বারা প্রতিবিম্ব ব্যবহার করা হবে।
— জেরোম হালটম

2
ডেটা স্ট্রিম কোনও বড় বিষয় নয়, কেন আপনি স্ট্রিংগুলি সংযোজন করতে হবে তা আমি দেখতে পাচ্ছি না ... স্ট্রিংয়ের সাম্যতা পরীক্ষা করা সেখানে সর্বাধিক অনুকূলিত অপারেশনগুলির একটি .... আপনার প্রতিচ্ছবি সহ একটি পয়েন্ট থাকতে পারে ... তবে সম্পূর্ণ সিরিয়ালাইজেশন অন্যান্য পদ্ধতির চেয়ে খারাপ "আদেশের আদেশ" হবে না। আপনি যদি পারফরম্যান্সের সমস্যায় সন্দেহ করেন তবে আপনার বেঞ্চমার্কগুলি করা উচিত ... আমি এই পদ্ধতিটির সাথে পারফরম্যান্সের সমস্যাগুলির
— মুখোমুখি হই নি

12
আমি +1এটি কেবল কারণ এটি আমি কোনও মান-ভিত্তিক সাম্যতা তুলনা এইভাবে করার কথা ভাবি নি। এটি দুর্দান্ত এবং সাধারণ। এই কোড সহ কিছু মানদণ্ড দেখতে ঝরঝরে হতে চাই।
— থমাস

1
এটি কোনও ভাল সমাধান নয় কারণ উভয় সিরিয়ালাইজেশন একইভাবে ভুল হতে পারে। উদাহরণস্বরূপ উত্স অবজেক্টের কিছু বৈশিষ্ট্যগুলি সিরিয়ালযুক্ত করা যায় নি এবং যখন ডিসিরিয়ালাইজড করা হবে তখন গন্তব্য অবজেক্টে বাতিল হয়ে যাবে। এই জাতীয় ক্ষেত্রে, স্ট্রিংয়ের সাথে তুলনা করা আপনার পরীক্ষাটি পাস হবে তবে উভয় অবজেক্ট আসলে একই নয়!
— stackMeUp

35

আপনি এই সমস্যাটি সমাধানের জন্য এক্সটেনশন পদ্ধতি, পুনরাবৃত্তি ব্যবহার করতে পারেন:

public static bool DeepCompare(this object obj, object another)
{     
  if (ReferenceEquals(obj, another)) return true;
  if ((obj == null) || (another == null)) return false;
  //Compare two object's class, return false if they are difference
  if (obj.GetType() != another.GetType()) return false;

  var result = true;
  //Get all properties of obj
  //And compare each other
  foreach (var property in obj.GetType().GetProperties())
  {
      var objValue = property.GetValue(obj);
      var anotherValue = property.GetValue(another);
      if (!objValue.Equals(anotherValue)) result = false;
  }

  return result;
 }

public static bool CompareEx(this object obj, object another)
{
 if (ReferenceEquals(obj, another)) return true;
 if ((obj == null) || (another == null)) return false;
 if (obj.GetType() != another.GetType()) return false;

 //properties: int, double, DateTime, etc, not class
 if (!obj.GetType().IsClass) return obj.Equals(another);

 var result = true;
 foreach (var property in obj.GetType().GetProperties())
 {
    var objValue = property.GetValue(obj);
    var anotherValue = property.GetValue(another);
    //Recursion
    if (!objValue.DeepCompare(anotherValue))   result = false;
 }
 return result;
}

বা জেসন ব্যবহার করে তুলনা করুন (যদি বস্তুটি খুব জটিল হয়) আপনি নিউটনসফট.জসন ব্যবহার করতে পারেন:

public static bool JsonCompare(this object obj, object another)
{
  if (ReferenceEquals(obj, another)) return true;
  if ((obj == null) || (another == null)) return false;
  if (obj.GetType() != another.GetType()) return false;

  var objJson = JsonConvert.SerializeObject(obj);
  var anotherJson = JsonConvert.SerializeObject(another);

  return objJson == anotherJson;
}

1
প্রথম সমাধান দুর্দান্ত! আমি পছন্দ করি যে আপনাকে নিজেরাই বস্তুগুলিতে কোনও কোড যুক্ত করতে সিরিয়ালায়িত করতে বা প্রয়োগ করতে হবে না। আপনি যখন ইউনিট পরীক্ষার জন্য কেবল তুলনা করছেন তখনই উপযুক্ত। আমি কী কোনও সাধারণ তুলনা যুক্ত অবজলভাল এবং অন্য ভ্যালু উভয়ের সমান নাল যুক্ত করার পরামর্শ দিচ্ছি? এটি নাল করার চেষ্টা করার সময় নাল রেফারেন্সএক্সেপশন এড়ানো হবে।একুয়ালস () // রিচার্ড জাম্পস্টেটমেন্ট পুনরায় শেয়ার করলে অক্ষম করা হয় (اعتراض ভ্যালু == অন্য ভ্যালু) অব্যাহত থাকলে; // নাল রেফারেন্স গার্ড অন্যথায় যদি (! objValue.Equals (আরেকটি মূল্য)) ব্যর্থ (প্রত্যাশিত, বাস্তব);
— মার্ক কনওয়ে

3
DeepCompareকেবল CompareExপুনরাবৃত্তি কল করার পরিবর্তে ব্যবহার করার কোনও কারণ আছে কি ?
— এস্টোস্টোলোভ

3
এটি অকারণে পুরো কাঠামোটির তুলনা করতে পারে। এর সাথে প্রতিস্থাপন resultকরা return falseএটি আরও দক্ষ করে তুলবে।
— টিম সিলভেস্টার

24

আপনি যদি আইক্যাটেবল বাস্তবায়ন করতে না চান, আপনি সর্বদা সমস্ত বৈশিষ্ট্যের তুলনা করতে প্রতিবিম্ব ব্যবহার করতে পারেন: - যদি তারা মান ধরণের হয় তবে কেবল তাদের সাথে তুলনা করুন - যদি তারা রেফারেন্স টাইপ হয় তবে এর "অভ্যন্তরীণ" বৈশিষ্ট্যগুলি তুলনা করার জন্য ফাংশনটিকে পুনরাবৃত্তভাবে কল করুন ।

আমি পারফরম্যান্স নিয়ে ভাবছি না, সরলতার কথা ভাবছি। এটি নির্ভর করে তবে আপনার সামগ্রীর সঠিক নকশার উপর। এটি আপনার বস্তুর আকারের উপর নির্ভর করে জটিল হয়ে উঠতে পারে (উদাহরণস্বরূপ যদি বৈশিষ্ট্যের মধ্যে চক্রীয় নির্ভরতা থাকে)। তবে এখানে বেশ কয়েকটি সমাধান রয়েছে যা আপনি এটির মতো ব্যবহার করতে পারেন:

আর একটি বিকল্প হ'ল পাঠ্য হিসাবে বস্তুকে সিরিয়ালাইজ করা, উদাহরণস্বরূপ JSON.NET ব্যবহার করা, এবং সিরিয়ালাইজেশন ফলাফলের সাথে তুলনা করা। (JSON.NET বৈশিষ্ট্যের মধ্যে চক্রীয় নির্ভরতা পরিচালনা করতে পারে)।

আমি জানি না দ্রুততম দ্বারা আপনি এটি বাস্তবায়নের দ্রুততম উপায় বা একটি কোড যা দ্রুত চলে mean আপনার যদি প্রয়োজন হয় তা জানার আগে আপনার অনুকূলিত হওয়া উচিত নয়। অকালীন অপটিমাইজেশন হ'ল সমস্ত অশুভের মূল


1
আমি দৃly়ভাবে মনে করি যে একটি IEquatable<T>বাস্তবায়ন অকাল অনুকূলকরণের ক্ষেত্রে যোগ্যতা অর্জন করে। প্রতিবিম্ব মারাত্মকভাবে ধীর হবে। Equalsকাস্টম মান ধরণের জন্য ডিফল্ট বাস্তবায়ন প্রতিবিম্ব ব্যবহার করে; মাইক্রোসফ্ট নিজেরাই এটিকে কার্য সম্পাদনের জন্য ওভাররাইড করার পরামর্শ দেয়: " Equalsপদ্ধতির কার্যকারিতা উন্নত করতে কোনও নির্দিষ্ট ধরণের জন্য পদ্ধতির ওভাররাইড করুন এবং এই ধরণের সাম্যের ধারণাটি আরও ঘনিষ্ঠভাবে উপস্থাপন করুন।"
— ডগলাস

1
এটি সমান পদ্ধতিটি চালাতে চলেছে তার উপরে নির্ভর করে: 1, 10, 100, 100, এক মিলিয়ন? এটি একটি বড় পার্থক্য করতে হবে। তিনি যদি কিছু প্রয়োগ না করে জেনেরিক সমাধান ব্যবহার করতে পারেন তবে তিনি কিছু মূল্যবান সময় ব্যয় করবেন। যদি এটি খুব ধীর হয় তবে আইকুয়েটেবল বাস্তবায়নের সময় এসেছে (এবং সম্ভবত এমনকি ক্যাশেযোগ্য বা বুদ্ধিমান গেটহ্যাশকোড তৈরি করার চেষ্টাও করা হচ্ছে) প্রতিচ্ছবিটির গতি যতদূর আমি অবশ্যই সম্মত করতে হবে এটি ধীর ... বা অনেক ধীর, আপনি কীভাবে এটি করেন তার উপর নির্ভর করে ( যেমন প্রপার্টিআইনফোস ধরণগুলি পুনরায় ব্যবহার করা ইত্যাদি,
— জোটাবে

@ মূল্যবান It এটি করে। দয়া করে প্রকল্পের বিষয়বস্তু দেখুন। উদাহরণস্বরূপ টেস্টগুলি ডকুমেন্ট করার একটি ভাল উপায়। তবে এর চেয়ে ভাল, আপনি যদি এটি সন্ধান করেন তবে আপনি একটি .chm সহায়তা ফাইল পাবেন। সুতরাং এই প্রকল্পের বেশিরভাগ প্রকল্পের তুলনায় অনেক ভাল ডকুমেন্টেশন রয়েছে।
— জোটাবি

দুঃখিত আপনি ঠিক বলেছেন, আমি পুরোপুরি "উইকি" ট্যাবটি মিস করেছি। রিডমিমে জিনিস লেখার জন্য আমি অভ্যস্ত।
— মূল্যবান 7

9

উভয় অবজেক্টকে সিরিয়াল করুন এবং ফলাফলযুক্ত স্ট্রিংগুলি @ জোয়েলফ্যানের সাথে তুলনা করুন

এটি করার জন্য, এর মতো একটি স্ট্যাটিক ক্লাস তৈরি করুন এবং সমস্ত বস্তু প্রসারিত করতে এক্সটেনশনগুলি ব্যবহার করুন (যাতে আপনি কোনও ধরণের অবজেক্ট, সংগ্রহ ইত্যাদি পদ্ধতিতে পাস করতে পারেন)

using System;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;

public static class MySerializer
{
    public static string Serialize(this object obj)
    {
        var serializer = new DataContractJsonSerializer(obj.GetType());
        using (var ms = new MemoryStream())
        {
            serializer.WriteObject(ms, obj);
            return Encoding.Default.GetString(ms.ToArray());
        }
    }
}

আপনি অন্য কোনও ফাইলে এই স্থিত শ্রেণিকে একবার উল্লেখ করলে আপনি এটি করতে পারেন:

Person p = new Person { Firstname = "Jason", LastName = "Argonauts" };
Person p2 = new Person { Firstname = "Jason", LastName = "Argonaut" };
//assuming you have already created a class person!
string personString = p.Serialize();
string person2String = p2.Serialize();

এখন আপনি কেবল ব্যবহার করতে পারেন .একটি তুলনা করার জন্য যোগ্যতা। আমি বস্তুগুলি খুব সংগ্রহে রয়েছে কিনা তা যাচাই করার জন্য এটি ব্যবহার করি। এটি সত্যিই ভাল কাজ করে।


যদি বস্তুর সামগ্রীগুলি ভাসমান পয়েন্ট সংখ্যাগুলির অ্যারে হয়। এগুলিকে স্ট্রিংয়ে রূপান্তর করতে এটি অত্যন্ত অদক্ষ এবং রূপান্তরটি সংজ্ঞায়িত রূপান্তরের সাপেক্ষে CultrureInfo। এটি কেবল তখনই কাজ করবে যদি অভ্যন্তরীণ ডেটা বেশিরভাগ স্ট্রিং এবং পূর্ণসংখ্যা হয়। অন্যথায় এটি একটি বিপর্যয় হবে।
— জন আলেক্সিউ

3
যদি কোনও নতুন পরিচালক আপনাকে সি # কেটে ফেলা এবং পাইথনের সাথে এটি প্রতিস্থাপন করতে বলে What বিকাশকারী হিসাবে, আমাদের শিখতে হবে যে প্রশ্নগুলি কোথাও থামতে হলে কী হয়। পরের দিকে, সমস্যার সমাধান করুন। আপনি যদি কখনও সময় পান তবে এতে ফিরে আসুন ...
— ozzy432836

2
পাইথন সিনট্যাক্স এবং ব্যবহারের ক্ষেত্রে ম্যাটল্যাবের মতো like স্থির প্রকারের নিরাপদ ভাষা থেকে পাইথনের মতো মিশ্মশ স্ক্রিপ্টে স্থানান্তরিত করার জন্য খুব যুক্তিসঙ্গত কারণ অবশ্যই থাকতে হবে।
— জন আলেক্সিউ

5

আমি ধরে নেব আপনি আক্ষরিকভাবে একই জিনিসগুলিকে উল্লেখ করছেন না

Object1 == Object2

আপনি দুজনের মধ্যে একটি স্মৃতি তুলনা করতে ভাবতে পারেন

memcmp(Object1, Object2, sizeof(Object.GetType())

তবে এটি সি # :) তেও আসল কোড নয়। যেহেতু আপনার সমস্ত ডেটা সম্ভবত স্তূপে তৈরি করা হয়েছে, স্মৃতিটি সংক্ষিপ্ত নয় এবং আপনি কেবল দুটি বস্তুর সমতার তুলনা করতে পারবেন না অজ্ঞেয় পদ্ধতিতে। আপনাকে প্রতিটি মানকে একবারে একটি কাস্টম পদ্ধতিতে তুলনা করতে হবে।

IEquatable<T>আপনার শ্রেণিতে ইন্টারফেস যুক্ত করার বিষয়টি বিবেচনা করুন এবং Equalsআপনার ধরণের জন্য একটি পছন্দসই পদ্ধতিটি নির্ধারণ করুন। তারপরে, সেই পদ্ধতিতে, প্রতিটি মান ম্যানুয়াল পরীক্ষা করে। যোগ IEquatable<T>আবার ঘিরা ধরনের যদি আপনি এবং প্রক্রিয়ার পুনরাবৃত্তি করতে পারেন।

class Foo : IEquatable<Foo>
{
  public bool Equals(Foo other)
  {
    /* check all the values */
    return false;
  }
}


3

বস্তুর তুলনা করার জন্য আমি এটি নীচের ফাংশনটি পেয়েছি।

 static bool Compare<T>(T Object1, T object2)
 {
      //Get the type of the object
      Type type = typeof(T);

      //return false if any of the object is false
      if (object.Equals(Object1, default(T)) || object.Equals(object2, default(T)))
         return false;

     //Loop through each properties inside class and get values for the property from both the objects and compare
     foreach (System.Reflection.PropertyInfo property in type.GetProperties())
     {
          if (property.Name != "ExtensionData")
          {
              string Object1Value = string.Empty;
              string Object2Value = string.Empty;
              if (type.GetProperty(property.Name).GetValue(Object1, null) != null)
                    Object1Value = type.GetProperty(property.Name).GetValue(Object1, null).ToString();
              if (type.GetProperty(property.Name).GetValue(object2, null) != null)
                    Object2Value = type.GetProperty(property.Name).GetValue(object2, null).ToString();
              if (Object1Value.Trim() != Object2Value.Trim())
              {
                  return false;
              }
          }
     }
     return true;
 }

আমি এটি ব্যবহার করছি এবং এটি আমার পক্ষে ভাল কাজ করছে।


1
প্রথমটির ifঅর্থ Compare(null, null) == falseযা আমি প্রত্যাশা করি না।
— টিম সিলভেস্টার

3

ইতিমধ্যে এখানে দেওয়া কয়েকটি উত্তরগুলির ভিত্তিতে আমি বেশিরভাগই জোয়েলফানের উত্তরটি ফিরে আসার সিদ্ধান্ত নিয়েছি । আমি এক্সটেনশন পদ্ধতিগুলি পছন্দ করি এবং এগুলি আমার জন্য দুর্দান্ত কাজ করে যখন অন্য কোনও সমাধান আমার জটিল শ্রেণীর তুলনা করার জন্য তাদের ব্যবহার করে না।

এক্সটেনশন পদ্ধতি

using System.IO;
using System.Xml.Serialization;

static class ObjectHelpers
{
    public static string SerializeObject<T>(this T toSerialize)
    {
        XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());

        using (StringWriter textWriter = new StringWriter())
        {
            xmlSerializer.Serialize(textWriter, toSerialize);
            return textWriter.ToString();
        }
    }

    public static bool EqualTo(this object obj, object toCompare)
    {
        if (obj.SerializeObject() == toCompare.SerializeObject())
            return true;
        else
            return false;
    }

    public static bool IsBlank<T>(this T obj) where T: new()
    {
        T blank = new T();
        T newObj = ((T)obj);

        if (newObj.SerializeObject() == blank.SerializeObject())
            return true;
        else
            return false;
    }

}

ব্যবহারের উদাহরণ

if (record.IsBlank())
    throw new Exception("Record found is blank.");

if (record.EqualTo(new record()))
    throw new Exception("Record found is blank.");

2

আমি বলতে চাই যে:

Object1.Equals(Object2)

আপনি যা খুঁজছেন তা হবে। আপনি যদি বস্তুগুলি একইরকম কিনা তা আপনি যদি সন্ধান করছেন তবে এটিই আপনি জিজ্ঞাসা করছেন বলে মনে হচ্ছে।

যদি আপনি দেখতে চান যে সমস্ত শিশু অবজেক্ট একইরূপে রয়েছে, তবে সেটিকে Equals()পদ্ধতিটি দিয়ে একটি লুপের মাধ্যমে চালান ।


2
যদি এবং কেবলমাত্র তারা সমানগুলির একটি অ-রেফারেন্স সমতা ওভারলোড সরবরাহ করে।
— user7116

প্রতিটি শ্রেণিকে অবশ্যই তুলনার নিজস্ব পদ্ধতি বাস্তবায়ন করতে হবে। যদি লেখকের ক্লাসগুলির সমান () পদ্ধতির জন্য কোনও ওভাররাইড না থাকে তবে তারা System.Object () বর্গের মৌলিক পদ্ধতি ব্যবহার করবে, যার ফলে যুক্তি ত্রুটি হতে পারে।
— Dima

2
public class GetObjectsComparison
{
    public object FirstObject, SecondObject;
    public BindingFlags BindingFlagsConditions= BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
}
public struct SetObjectsComparison
{
    public FieldInfo SecondObjectFieldInfo;
    public dynamic FirstObjectFieldInfoValue, SecondObjectFieldInfoValue;
    public bool ErrorFound;
    public GetObjectsComparison GetObjectsComparison;
}
private static bool ObjectsComparison(GetObjectsComparison GetObjectsComparison)
{
    GetObjectsComparison FunctionGet = GetObjectsComparison;
    SetObjectsComparison FunctionSet = new SetObjectsComparison();
    if (FunctionSet.ErrorFound==false)
        foreach (FieldInfo FirstObjectFieldInfo in FunctionGet.FirstObject.GetType().GetFields(FunctionGet.BindingFlagsConditions))
        {
            FunctionSet.SecondObjectFieldInfo =
            FunctionGet.SecondObject.GetType().GetField(FirstObjectFieldInfo.Name, FunctionGet.BindingFlagsConditions);

            FunctionSet.FirstObjectFieldInfoValue = FirstObjectFieldInfo.GetValue(FunctionGet.FirstObject);
            FunctionSet.SecondObjectFieldInfoValue = FunctionSet.SecondObjectFieldInfo.GetValue(FunctionGet.SecondObject);
            if (FirstObjectFieldInfo.FieldType.IsNested)
            {
                FunctionSet.GetObjectsComparison =
                new GetObjectsComparison()
                {
                    FirstObject = FunctionSet.FirstObjectFieldInfoValue
                    ,
                    SecondObject = FunctionSet.SecondObjectFieldInfoValue
                };

                if (!ObjectsComparison(FunctionSet.GetObjectsComparison))
                {
                    FunctionSet.ErrorFound = true;
                    break;
                }
            }
            else if (FunctionSet.FirstObjectFieldInfoValue != FunctionSet.SecondObjectFieldInfoValue)
            {
                FunctionSet.ErrorFound = true;
                break;
            }
        }
    return !FunctionSet.ErrorFound;
}

পুনরাবৃত্তি নীতি ব্যবহার করে।
— মাতান জাস্টেম

1

এটি করার একটি উপায় হ'ল Equals()জড়িত প্রতিটি প্রকারের উপর ওভাররাইড করা। উদাহরণস্বরূপ, আপনার শীর্ষ স্তরের অবজেক্টটি সমস্ত 5 শিশু অবজেক্টের পদ্ধতিতে Equals()কল করতে ওভাররাইড করবে Equals()। এই বিষয়গুলিকে সমস্তগুলি Equals()পাশাপাশি ওভাররাইড করা উচিত , তারা ধরে নিচ্ছে যে তারা কাস্টম অবজেক্টস এবং তাই যতক্ষণ না পুরো স্তরক্রমকে কেবল শীর্ষ স্তরের বস্তুগুলিতে সাম্যতা পরীক্ষা করে পরীক্ষা করা যায়।



1

জোনাথনের উদাহরণের জন্য ধন্যবাদ। আমি এটিকে সমস্ত ক্ষেত্রে (অ্যারে, তালিকা, অভিধান, আদিম ধরণের) প্রসারিত করেছি।

এটি সিরিয়ালাইজেশন ব্যতীত তুলনা এবং তুলনামূলক অবজেক্টগুলির জন্য কোনও ইন্টারফেসের প্রয়োগের প্রয়োজন হয় না।

        /// <summary>Returns description of difference or empty value if equal</summary>
        public static string Compare(object obj1, object obj2, string path = "")
        {
            string path1 = string.IsNullOrEmpty(path) ? "" : path + ": ";
            if (obj1 == null && obj2 != null)
                return path1 + "null != not null";
            else if (obj2 == null && obj1 != null)
                return path1 + "not null != null";
            else if (obj1 == null && obj2 == null)
                return null;

            if (!obj1.GetType().Equals(obj2.GetType()))
                return "different types: " + obj1.GetType() + " and " + obj2.GetType();

            Type type = obj1.GetType();
            if (path == "")
                path = type.Name;

            if (type.IsPrimitive || typeof(string).Equals(type))
            {
                if (!obj1.Equals(obj2))
                    return path1 + "'" + obj1 + "' != '" + obj2 + "'";
                return null;
            }
            if (type.IsArray)
            {
                Array first = obj1 as Array;
                Array second = obj2 as Array;
                if (first.Length != second.Length)
                    return path1 + "array size differs (" + first.Length + " vs " + second.Length + ")";

                var en = first.GetEnumerator();
                int i = 0;
                while (en.MoveNext())
                {
                    string res = Compare(en.Current, second.GetValue(i), path);
                    if (res != null)
                        return res + " (Index " + i + ")";
                    i++;
                }
            }
            else if (typeof(System.Collections.IEnumerable).IsAssignableFrom(type))
            {
                System.Collections.IEnumerable first = obj1 as System.Collections.IEnumerable;
                System.Collections.IEnumerable second = obj2 as System.Collections.IEnumerable;

                var en = first.GetEnumerator();
                var en2 = second.GetEnumerator();
                int i = 0;
                while (en.MoveNext())
                {
                    if (!en2.MoveNext())
                        return path + ": enumerable size differs";

                    string res = Compare(en.Current, en2.Current, path);
                    if (res != null)
                        return res + " (Index " + i + ")";
                    i++;
                }
            }
            else
            {
                foreach (PropertyInfo pi in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
                {
                    try
                    {
                        var val = pi.GetValue(obj1);
                        var tval = pi.GetValue(obj2);
                        if (path.EndsWith("." + pi.Name))
                            return null;
                        var pathNew = (path.Length == 0 ? "" : path + ".") + pi.Name;
                        string res = Compare(val, tval, pathNew);
                        if (res != null)
                            return res;
                    }
                    catch (TargetParameterCountException)
                    {
                        //index property
                    }
                }
                foreach (FieldInfo fi in type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
                {
                    var val = fi.GetValue(obj1);
                    var tval = fi.GetValue(obj2);
                    if (path.EndsWith("." + fi.Name))
                        return null;
                    var pathNew = (path.Length == 0 ? "" : path + ".") + fi.Name;
                    string res = Compare(val, tval, pathNew);
                    if (res != null)
                        return res;
                }
            }
            return null;
        }

ভান্ডার তৈরি করা কোডটির অনুলিপি করার জন্য


1

আপনি এখন json.net ব্যবহার করতে পারেন। শুধু নুগেটে যান এবং এটি ইনস্টল করুন।

এবং আপনি এর মতো কিছু করতে পারেন:

    public bool Equals(SamplesItem sampleToCompare)
    {
        string myself = JsonConvert.SerializeObject(this);
        string other = JsonConvert.SerializeObject(sampleToCompare);

        return myself == other;
    }

আপনি ফ্যানসিয়ার পেতে চাইলে আপনি সম্ভবত অবজেক্টের জন্য একটি এক্সটেনশন পদ্ধতি তৈরি করতে পারেন। দয়া করে মনে রাখবেন এটি কেবল সর্বজনীন বৈশিষ্ট্যের সাথে তুলনা করে। আপনি যদি তুলনাটি করেন তবে আপনি যদি কোনও সরকারী সম্পত্তি উপেক্ষা করতে চান তবে আপনি [জসনআইগনোর] বৈশিষ্ট্যটি ব্যবহার করতে পারেন।


আপনার যদি আপনার অবজেক্টে তালিকা থাকে এবং সেগুলির তালিকাগুলি থাকে তবে উভয় অবজেক্টকে অতিক্রম করার চেষ্টা করা একটি দুঃস্বপ্ন হতে চলেছে। আপনি যদি উভয়কে সিরিয়ালাইজ করেন এবং তারপরে তুলনা করেন আপনাকে সেই দৃশ্যের সাথে ডিল করতে হবে না।
— ashlar64

আপনার জটিল অবজেক্টের যদি একটি অভিধান থাকে তবে আমি বিশ্বাস করি না। নেট সিরিয়ালাইজার এটি সিরিয়াল করতে পারে। জসন সিরিয়ালাইজার পারেন।
— ashlar64
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.