Creating a distinct list of custom type in C#
I receive a List of en entity framework type and want to only return the distinct values from the List. I'm using the following approach, however it's not uniquifying the list. Any suggestions?
Param: List<Flag> flags
List<Flag> distinctFlags = flags.Distinct().ToList();
The values of Flag are as follows: ID, Flag, FlagValue. Could I use linq in this instance?
Thanks.
Assuming Flag
is one of your entity models, you could use a partial
class
and override Equals
and GetHashCode
. This also assumes that you have an Id
property on on your Flag
class
which uniquely identities it.
//this namespace MUST match the namespace of your entity model.
namespace Your.Entity.Model.Namespace
{
public partial class Flag
{
public override bool Equals(object obj)
{
var item = obj as Flag;
if (item == null)
{
return false;
}
return this.Id.Equals(item.Id);
}
public override int GetHashCode()
{
return this.Id.GetHashCode();
}
}
}
Usage would look like this
List<Flag> distinctFlags = allFlags.Distinct().ToList();
Probably flags
is a list of reference type, and distinct does not work as you expect!
This because Distinct() work not on the value of the flag in the list, but on its memory references (that are all differents).
You have to write a comparer class that teach to Distinct how to compare equal flag. Suppose you have this flag class:
public class flag
{
public string Name { get; set; }
public string Code { get; set; }
}
you should create a comparer class like this:
class FlagComparer : IEqualityComparer<flag>
{
// Products are equal if their names and product numbers are equal.
public bool Equals(flag x, flag y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the products' properties are equal.
return x.Code == y.Code && x.Name == y.Name;
}
}
and the call your statement:
List distinctFlags = flags.Distinct(new FlagComparer ()).ToList();
In this way, Distinct method know exactly how to compare equals flag istance.
UPDATE
Based on your comment, if you wanto to follow my suggestion, you should write the comparer base as follow:
class FlagComparer : IEqualityComparer<flag>
{
// Products are equal if their names and product numbers are equal.
public bool Equals(flag x, flag y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the products' properties are equal.
return x.HostID == y.HostID && x.RuleID == y.RuleID && x.Flag == y.Flag && x.FlagValue == y.FlagValue;
}
}
Of course, every property must be a value type.
Take a look here to clarify yourself:
- Value Type
- Reference type