The Distinct of Linq is too bad.

Source: Internet
Author: User

 

Suppose we have a class: Product

 

Public class Product

{

Public string Id {get; set ;}

Public string Name {get; set ;}

} The Main function is as follows:

 

Static void Main ()

{

List <Product> products = new List <Product> ()

{

New Product () {Id = "1", Name = "n1 "},

New Product () {Id = "1", Name = "n2 "},

New Product () {Id = "2", Name = "n1 "},

New Product () {Id = "2", Name = "n2 "},

};

 

Var distinctProduct = products. Distinct ();

 

Console. ReadLine ();

}

The result of distinctProduct is:

Because Distinct compares the reference of the Product object by default, four data records are returned.

 

What should we do if we want to return a unique product with the Id?

 

 

 

 

The Distinct method has another overload:

 

// Compare the value by using the specified System. Collections. Generic. IEqualityComparer <T>

// Return non-repeating elements in the sequence.

Public static IEnumerable <TSource> Distinct <TSource> (this IEnumerable <TSource> source, IEqualityComparer <TSource> comparer); this overload receives an IEqualityComparer parameter.

 

If you want to filter by Id, you should create the ProductIdComparer class as follows:

 

Public class ProductIdComparer: IEqualityComparer <Product>

{

Public bool Equals (Product x, Product y)

{

If (x = null)

Return y = null;

Return x. Id = y. Id;

}

 

Public int GetHashCode (Product obj)

{

If (obj = null)

Return 0;

Return obj. Id. GetHashCode ();

}

}

 

Var distinctProduct = products. Distinct (new ProductIdComparer (); the result is as follows:

 

 

 

 

What if we want to filter duplicates by Name?

 

Obviously, you need to add another class ProductNameComparer.

 

Can I use generic classes ??

 

 

The new class PropertyComparer <T> inherits IEqualityComparer <T> as follows:

 

Public class PropertyComparer <T>: IEqualityComparer <T>

{

Private PropertyInfo _ PropertyInfo;

 

/// <Summary>

/// Obtain the PropertyInfo object through propertyName /// </summary>

/// <Param name = "propertyName"> </param>

Public PropertyComparer (string propertyName)

{

_ PropertyInfo = typeof (T). GetProperty (propertyName,

BindingFlags. GetProperty | BindingFlags. Instance | BindingFlags. Public );

If (_ PropertyInfo = null)

{

Throw new ArgumentException (string. Format ("{0} is not a property of type {1 }.",

PropertyName, typeof (T )));

}

}

 

# Region IEqualityComparer <T> Members

 

Public bool Equals (T x, T y)

{

Object xValue = _ PropertyInfo. GetValue (x, null );

Object yValue = _ PropertyInfo. GetValue (y, null );

 

If (xValue = null)

Return yValue = null;

 

Return xValue. Equals (yValue );

}

 

Public int GetHashCode (T obj)

{

Object propertyValue = _ PropertyInfo. GetValue (obj, null );

 

If (propertyValue = null)

Return 0;

Else

Return propertyValue. GetHashCode ();

}

 

# Endregion

}

 

 

The main difference is that the rewritten Equals and GetHashCode use the attribute value comparison.

 

You only need:

 

// Var distinctProduct = products. Distinct (new PropertyComparer <Product> ("Id "));

Var distinctProduct = products. Distinct (new PropertyComparer <Product> ("Name "));

 

The result is as follows:

 

 

 

 

Why does Microsoft not provide the PropertyEquality <T> class?

 

According to the above logic, this class should not be very complicated. Careful students can find that PropertyEquality uses reflection in a large number. Every time you get the attribute value

_ PropertyInfo. GetValue (x, null );

 

As you can imagine, if there are many records to filter, the performance will undoubtedly be affected.

 

To improve performance, you can use the expression tree to change the reflection call to a delegate call,

 

The Code is as follows:

 

 

 

Public class FastPropertyComparer <T>: IEqualityComparer <T>

{

Private Func <T, Object> getPropertyValueFunc = null;

 

/// <Summary>

/// Obtain the PropertyInfo object through propertyName

/// </Summary>

/// <Param name = "propertyName"> </param>

Public FastPropertyComparer (string propertyName)

{

PropertyInfo _ PropertyInfo = typeof (T). GetProperty (propertyName,

BindingFlags. GetProperty | BindingFlags. Instance | BindingFlags. Public );

If (_ PropertyInfo = null)

{

Throw new ArgumentException (string. Format ("{0} is not a property of type {1 }.",

PropertyName, typeof (T )));

}

 

ParameterExpression expPara = Expression. Parameter (typeof (T), "obj ");

MemberExpression me = Expression. Property (expPara, _ PropertyInfo );

GetPropertyValueFunc = Expression. Lambda <Func <T, object> (me, expPara). Compile ();

}

 

# Region IEqualityComparer <T> Members

 

Public bool Equals (T x, T y)

{

Object xValue = getPropertyValueFunc (x );

Object yValue = getPropertyValueFunc (y );

 

If (xValue = null)

Return yValue = null;

 

Return xValue. Equals (yValue );

}

 

Public int GetHashCode (T obj)

{

Object propertyValue = getPropertyValueFunc (obj );

 

If (propertyValue = null)

Return 0;

Else

Return propertyValue. GetHashCode ();

}

 

# Endregion

}

 

You can see that only getPropertyValueFunc (obj) is required to get the value.

 

When using:

 

Var distinctProduct = products. Distinct (new FastPropertyComparer <Product> ("Id"). ToList ();

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.