How to Use LINQ methods to compare objects of custom types

Source: Internet
Author: User

Original article:Http://blogs.msdn.com/csharpfaq/archive/2009/03/25/how-to-use-linq-methods-to-compare-objects-of-custom-types.aspx

Translation:Http://www.cnblogs.com/tianfan/

LINQ provides a convenient syntax and incluuseful methods for operating with collections of objects. However, to be correctly processed by LINQ comparison methods such as distinct or intersect, a type must satisfy certain requirements.

Let's take a look at the distinct method, which returns all distinct objects from a collection.

List <int> numbers = new list <int> {1, 1, 2, 3 };

VaR distinctnumbers = numbers. Distinct ();

Foreach (VAR number in distinctnumbers)

Console. writeline (number );

The output is:

1

2

3

But what if you want to use the distinct method for a collection of objects of your own type? For example, like this:

Class number

{

Public int digital {Get; set ;}

Public String textual {Get; set ;}

}

Class Program

{

Static void main (string [] ARGs)

{

List <number> numbers = new list <number> {

New number {digital = 1, textual = "one "},

New number {digital = 1, textual = "one "},

New number {digital = 2, textual = "two "},

New number {digital = 3, textual = "three "},

};

VaR distinctnumbers = numbers. Distinct ();

Foreach (VAR number in distinctnumbers)

Console. writeline (number. Digital );

}

}

The Code compiles, but the output is different:

1

1

2

3

Why did that happen? The answer is in the LINQ implementation details. To be correctly processed by the distinct method, a type must implement the iequatable <t> interface and provide its own equals and gethashcode methods.

So, the number class from the previous example shocould actually look like this:

Class number: iequatable <number>

{

Public int digital {Get; set ;}

Public String textual {Get; set ;}

Public bool equals (number other)

{

// Check whether the compared object is null.

If (object. referenceequals (Other, null) return false;

// Check whether the compared object references the same data.

If (object. referenceequals (this, other) return true;

// Check whether the objects 'properties are equal.

Return digital. Equals (other. Digital )&&

Textual. Equals (other. textual );

}

// If equals returns true for a pair of objects,

// Gethashcode must return the same value for these objects.

Public override int gethashcode ()

{

// Get the hash code for the textual field if it is not null.

Int hashtextual = textual = NULL? 0: Textual. gethashcode ();

// Get the hash code for the digital field.

Int hashdigital = digital. gethashcode ();

// Calculate the hash code for the object.

Return hashdigital ^ hashtextual;

}

}

But what if you cannot modify the type? What if it was provided by a library and you have no way of implementing the iequatable <t> interface in this type? The answer is to create your own algorithm ity comparer and pass it as a parameter to the distinct method.

The specified ity comparer must implement the iequalitycomparer <t> interface and, again, provide gethashcode and equals methods.

Here is how the capacity ity comparer for the original number class might look:

Class numbercomparer: iequalitycomparer <number>

{

Public bool equals (number X, number y)

{

If (object. referenceequals (x, y) return true;

If (object. referenceequals (x, null) |

Object. referenceequals (Y, null ))

Return false;

Return X. Digital = Y. Digital & X. textual = Y. textual;

}

Public int gethashcode (Number number)

{

If (object. referenceequals (number, null) return 0;

Int hashtextual = number. textual = NULL

? 0: Number. textual. gethashcode ();

Int hashdigital = number. Digital. gethashcode ();

Return hashtextual ^ hashdigital;

}

}

And don't forget to pass the comparer to the distinct method:

VaR distinctnumbers = numbers. Distinct (New numbercomparer ());

Of course, these rules don't just apply to the distinct method. for example, the same is true for the contains, except T, intersect, and Union methods. in general, if you see that a LINQ method has an overload that accepts the iequalitycomparer <t> parameter, it probably means that to use it for your own data types you need to either implement iequatable <t> in your class or create your own capacity ity comparer.

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.