Search code examples
c#listgenericsrefactoring

Refactor to generic method with Predicate<T> and inner condition variable


Consider removing duplicated elements of List from a specific class like below:

private List<MyClass> RemoveDuplicatedMyClass(List<MyClass> myObjects)
{
    List<MyClass> uniqueMyClasses = new List<MyClass>();
    foreach (MyClass item in myObjects)
    {
        if (uniqueMyClasses.FindAll(itm => itm.myAttribute == item.myAttribute).Count == 0)
        {
            uniqueMyClasses.Add(item);
        }
    }
    return uniqueMyClasses;
}

I want to refactor RemoveDuplicatedMyClass to a generic version RemoveDuplicatedItems like below:

public static List<T> RemoveDuplicatedItems<T>(List<T> items, Predicate<T> match)
{
    if (items == null)
    {
        return new List<T>();
    }
    List<T> uniqueItems = new List<T>();
    foreach (T item in items)
    {
        // Check if item exists (= already added)! If not add to unique list.
        if (uniqueItems.FindAll(match).Count < 1)
        {
            uniqueItems.Add(item);
        }
    }
    return uniqueItems;
}

Problem: How can I get access to Predicate<T> match with the inner T item?


Solution

  • As guys mentioned in comments, it's a good idea to use Enumerable.DistinctBy and one solution is to use dynamic objects:

    static List<dynamic> RemoveDuplicatedItems(List<dynamic>? items)
    {
        if (items == null)
        {
            return new List<dynamic>();
        }
        return items.DistinctBy(x=>x.MyAttribute).ToList();
    }
    

    and another and I think better option is to use abstraction, if you have some common properties between your classes you can create interface and define type of T as inheritor of that interface:

    static List<T> RemoveDuplicatedItems<T>(List<T>? items) where T:ISomeCommonInterface
    {
        if (items == null)
        {
            return new List<T>();
        }
        return items.DistinctBy(x=>x.MyAttribute).ToList();;
    }