مقدمه ای برGeneric IEqualityComparer

سه شنبه 14 دی 1395

در این مقاله قصد داریم شما را با Generic IEqualityComparer آشنا کنیم که در زیر به صورت کامل برای شما توضیح میدهیم.IEqualityCompare یک اینترفیس بسیار مهم برای مقایسه taskها دردنیای LINQ است.

مقدمه ای برGeneric IEqualityComparer

متدهای توسعه یافته یک Overload با این نوع پارامتر ها را دارند : Contains, Distinct, Except, Intersect, GrouBy, GroupJoin, Join, SecuenceEqual, ToDictionary, ToLookUp و Union.

در LinQ تولید اینترفیس IEqualityComparer  یک کار خسته کننده است مخصوصا زمانی که ما زمان کافی نداریم.کلاس generic کار ما را در این ضمینه راحت میکند.

• پیاده سازی کلاسیک IEqualityComparer (برای فیلد ها)

•پیاده سازی جنریک IEqualityComparer (برای فیلد ها)

•  پیاده سازی کلاسیک IEqualityComparer (برای experssion ها)

• پیاده سازی جنریک IEqualityComparer (برای experssion ها)

• کلاس کد GenericIEqualityComparer 

پیاده سازی کلاسیک IEqualityComparer (برای فیلد ها) :

این مثال ، تولید customer های مختلف برای یک دنباله میباشد.

Class Customer :

public class Customer {  
    public int ID {  
        get;  
        set;  
    }  
    public string Name {  
        get;  
        set;  
    }  
    public decimal Sales {  
        get;  
        set;  
    }  
    public string City {  
        get;  
        set;  
    }  
    public static IEnumerable < Customer > GetData() {  
        return new List < Customer > () {  
            new Customer {  
                ID = 1, Name = "Philips", Sales = 2000000 m, City = "Madrid"  
            },  
            new Customer {  
                ID = 2, Name = "Pionner", Sales = 1000000 m, City = "Berlin"  
            },  
            new Customer {  
                ID = 3, Name = "Renault", Sales = 2000000 m, City = "Paris"  
            },  
            new Customer {  
                ID = 4, Name = "Sony Music", Sales = 500000 m, City = "London"  
            },  
            new Customer {  
                ID = 5, Name = "Sony SCEE", Sales = 2000000 m, City = "Tokio"  
            },  
            new Customer {  
                ID = 6, Name = "Pepsi", Sales = 9000000 m, City = "New York"  
            },  
            new Customer {  
                ID = 6, Name = "LG", Sales = 2000000 m, City = "Rome"  
            }  
        };  
    }  
}  

نکته :

 دو مشتری آخر دارای شناسه یکسان میباشند.

اگر ما  متد Distinct LinQ Extension را فراخوانی کنیم.،نتبجه ما یک دنباله با 7 المنت میشود و ما نمیتوانیم هیچ عضو متمایزی را پیدا کنیم.

دلیل آن این است که مقایسه های متمایز نمونه ها برای پیش فرض برای همه مختلف است.

using System;  
using System.Linq;  
using DAL;  
using static System.Console;  
namespace ConsoleClient {  
    class Program {  
        static void Main(string[] args) {  
            var customers = Customer.GetData();  
            WriteLine($ "There are {customers.Count()} customers.");  
            var customersDifferents = customers.Distinct();  
            WriteLine($ "There are {customersDifferents.Count()} DIFFERENT customers.");  
            Console.Read();  
        }  
    }  
}

حال ، به فیلد یا فیلد هایی که تفاوت ایجاد میکنند ،مانند ID فکر میکنیم.

IEqualityComparer  به ما در مدیریت و بهبود عملکرد ما تاثیر میگذارد.

public class CustomerForIDEqualityComparer: IEqualityComparer < Customer > {  
    public bool Equals(Customer x, Customer y) {  
        bool result = x.ID == y.ID;  
        return result;  
    }  
    public int GetHashCode(Customer obj) {  
        return obj.ID.GetHashCode();  
    }  
} 

نام کلاس IEqualityComparer هدف خود را برای ما بازگو میکند.

هر مشتری برای خود یک ID منحصر به فرد دارد.

میتوانیم کلاس های بیشتری برای OBJECT های مختلف و فیلد های مختلف داشته باشیم.

ما از کلاس IEqualityComparer خودمان استفاده میکنیم.

static void Main(string[] args) {  
    var customers = Customer.GetData();  
    WriteLine($ "There are {customers.Count()} customers.");  
    var customersDifferents = customers.Distinct(new CustomerForIDEqualityComparer()).ToList();  
    WriteLine($ "There are {customersDifferents.Count()} DIFFERENT customers.");  
    Console.Read();  
}  

نتیجه مطلوب است ، به دلیل آنکه ماتنها دو مشتری با id مختلف داشتیم.

پیاده سازی جنریک IEqualityComparer (برای فیلد ها) :

در اینجا باید GenericEqualityComparer را در Nuget دانلود کنیم.

دو راه حل را میشود انجام داد :

در SOLUTION بر روی refrence کلیک راست میکنیم و add refrence را میزنیم.

یا از طریق Package Manager Console :

دستور زیر را وارد کنید :

Install-Package MoralesLarios.GenericEqualityComparer

فضای نام این کلاس را وارد کنید :

using MoralesLarios.Generics  

مامثال قبل را تکرار کردیم اما این بار با استفاده از کلاس GenericEqualityComparer .

به یاد بیاورید که این کلاس نه تنها فقط برای فیلد هر مشتری یا هر فیلدهای ترکیبی کاربر مناسب است بلکه  برای هر فیلد کلاس یا هر فیلد ترکیبی دیگر کلا مناسب است.

کلاس GenericEqualityComparer  یک overload با Func<T, object> parameter دارد.

این نوع شبیه به (Select method (System.LinQ است.

مثال :

static void Main(string[] args) {  
    var customers = Customer.GetData();  
    // Field Generic Comparator  
    Func < Customer, object > fieldComparator = customer => customer.ID;  
    // Instanct GenericIEqualityComparerClass  
    GenericEqualityComparer < Customer > genericCustomerIEqualityComparer = new GenericEqualityComparer < Customer > (fieldComparator);  
    WriteLine($ "There are {customers.Count()} customers.");  
    var customersDifferents = customers.Distinct(genericCustomerIEqualityComparer).ToList();  
    WriteLine($ "There are {customersDifferents.Count()} DIFFERENT customers.");  
    Console.Read();  
}  

اولین مرحله ، ساخت  (FieldComparator (Func<T, object> است.

دومین مرحله ارث بری از کلاس GenericEqualityComparer  است.

TypeParameter شما customer است و پارامتر سازنده شما FieldComparator است.

نتیجه :

نتیجه یکسان است اما این کد خوانایی بیشتری دارد.

 پیاده سازی کلاسیک IEqualityComparer (برای experssion ها) :

ما پیاده سازی کلاسیک کلاس IEqualityComparer را انجام خواهیم داد. در مورد مثال، ما نیاز به مقایسه Customer ها داریم.

2 customer متفاوت اند اگر حرف اول نام آنها متفاوت باشد.

public class Customer1stCharNameComparer: IEqualityComparer < Customer > {  
    public bool Equals(Customer x, Customer y) {  
        bool result = x.Name ? [0] == y.Name ? [0];  
        return result;  
    }  
    public int GetHashCode(Customer obj) {  
        return obj.Name == null ? 0 : obj.Name[0].GetHashCode();  
    }  
}  
We do the same example, but with the IEqualityComparer  
for  
expression now: static void Main(string[] args) {  
    var customers = Customer.GetData();  
    WriteLine($ "There are {customers.Count()} customers.");  
    var customersDifferents = customers.Distinct(new Customer1stCharNameComparer()).ToList();  
    WriteLine($ "There are {customersDifferents.Count()} DIFFERENT customers.");  
    Console.Read();  
} 

نتیجه :

 پیاده سازی جنریک IEqualityComparer (برای experssion ها) :

برای experssion ها دامنه گسترده تر است و محدودیت ندارد.

GenericEqualityComparer دارای یک Overload با یک <Func<T, T, bool دارد. این پارامتر ها experssion مقایسه را نشان ما میدهد.

این مثال، مانند قبل اما با GenericEqualityComparer است.

static void Main(string[] args) {  
    var customers = Customer.GetData();  
    // Field Generic Comparator  
    Func < Customer, Customer, bool > expressionComparator = (customer1, customer2) => customer1.Name ? [0] == customer2.Name ? [0];  
    // Instanct GenericIEqualityComparerClass  
    GenericEqualityComparer < Customer > genericCustomerIEqualityComparer = new GenericEqualityComparer < Customer > (expressionComparator);  
    WriteLine($ "There are {customers.Count()} customers.");  
    var customersDifferents = customers.Distinct(genericCustomerIEqualityComparer).ToList();  
    WriteLine($ "There are {customersDifferents.Count()} DIFFERENT customers.");  
    Console.Read();  
} 

نتیجه یکسان  :

نتیجه مانند مورد قبل است اما بیشتر خواناتر است.

 کلاس کد GenericIEqualityComparer  :

تلاش میکنیم برای توضیح کد GenericEqualityComparer

using System;  
using System.Collections.Generic;  
namespace CodComun {  
    public class GenericEqualityComparer < T > : IEqualityComparer < T > {  
        private Func < T,  
        object > _virtualFieldComparator;  
        private Func < T,  
        T,  
        bool > _virtualFilterComparator;  
        public GenericEqualityComparer(Func < T, object > virtualFieldComparator) {  
            if (virtualFieldComparator == null) throw new ArgumentNullException(nameof(virtualFieldComparator), $ "{nameof(virtualFieldComparator)}  doesn't be null");  
            Reset();  
            this._virtualFieldComparator = virtualFieldComparator;  
        }  
        public GenericEqualityComparer(Func < T, T, bool > virtualFilterComparator) {  
            if (virtualFilterComparator == null) throw new ArgumentNullException(nameof(virtualFilterComparator), $ "{nameof(virtualFilterComparator)}  doesn't be null");  
            Reset();  
            this._virtualFilterComparator = virtualFilterComparator;  
        }  
        private void Reset() {  
            _virtualFieldComparator = null;  
            _virtualFilterComparator = null;  
        }  
        public bool Equals(T x, T y) {  
            bool result = false;  
            if (_virtualFieldComparator != null) result = _virtualFieldComparator(x).Equals(_virtualFieldComparator(y));  
            else result = _virtualFilterComparator(x, y);  
            return result;  
        }  
        public int GetHashCode(T obj) {  
            int result = 0;  
            if (_virtualFieldComparator != null) result = _virtualFieldComparator(obj).GetHashCode();  
            else result = _virtualFilterComparator(obj, obj).GetHashCode();  
            return result;  
        }  
    }  
}  

این کلاس  <IEqualityComparer<T را به صورت کلاسیک پیاده سازی میکند.

این دو فیلد private دارد.در این فیلدها مقدارهای دو کاربر ذخیره میشود.

 هرکدام از دو حالت کلاس : برای فیلدها یا برای Expression است.

این دو customer دارد برای فعال سازی حالت Field mode یا Expression mode.

و یک متد private دارد که تمام حالت ها را reset میکند.

در آخر، دو متد عمومی Equals و GetHashCode در <IEqualityComparer<T پیاده سازی میشوند.

و از اکشن encapsulate برای آن دو فیلد private استفاده میشود.

آموزش سی شارپ

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان
  • C#.net
  • 1k بازدید
  • 5 تشکر

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید