I need a generic class to compare two list instances. I have the code below, but it is quite messy and inefficient. How can I make it better and definitely faster? 

CallByName is an extension that uses reflection to get the property.

```
public class ListObjectComparator
{ 
    #region PROPRIETES

    public List<object> NewList {get; private set;}
    public List<object> RemovedList { get; private set; }
    public List<object> CommunList { get; private set; }

    #endregion

    #region METHODES PUBLICS

    public bool Run<T>(string iCommunTextPropertyName, List<T> iOriginalList, List<T> iNewList)
    {
        return Run(iCommunTextPropertyName, iOriginalList, iCommunTextPropertyName, iNewList);
    }

    public bool Run<T>(string iOriginalPropertyName, List<T> iOriginalList,string iNewPropertyName, List<T> iNewList)
    {
        if (iOriginalPropertyName.IsNotNull() &&
            iNewPropertyName.IsNotNull() &&
            iOriginalList != null &&
            iNewList != null)
        {
            NewList = new List<object>();
            RemovedList = new List<object>();
            CommunList = new List<object>();

            foreach (object originalItem in iOriginalList)
            {
                object research = iNewList.Where(a => a.CallByName(iNewPropertyName).ToString() == originalItem.CallByName(iOriginalPropertyName).ToString()).FirstOrDefault();
                if (research == null)
                {
                    RemovedList.Add(originalItem);
                }
                else
                {
                    CommunList.Add(research);
                }
            }

            foreach (object newItem in iNewList)
            {
                object research = iOriginalList.Where(a => a.CallByName(iOriginalPropertyName).ToString() == newItem.CallByName(iNewPropertyName).ToString()).FirstOrDefault();
                if (research == null) { NewList.Add(newItem); };

            }
            return true;
        }
        return false;
    }
}

```

Answer:

```
public class ListComparator<TOriginal,TNew>
{

    public ListComparator(IEnumerable<TOriginal> iOriginalList, Func<TOriginal, IComparable> iOriginalProperty, IEnumerable<TNew> iNewList, Func<TNew, IComparable> iNewProperty)
    {
        if (iOriginalProperty == null ||
            iNewProperty == null) { throw new ArgumentNullException(); };

            if (iOriginalList.IsNullOrEmpty() )
            {
                NewList = (iNewList != null) ? iNewList.ToList() : null;
                return;
            }

            if (iNewList.IsNullOrEmpty())
            {
                RemovedList = (iOriginalList != null) ? iOriginalList.ToList() : null;
                return;
            }

            NewList = (from tnew in iNewList.ToList()
                       join toriginal in iOriginalList.ToList()
                       on iNewProperty(tnew)
                       equals iOriginalProperty(toriginal) into gj
                       from item in gj.DefaultIfEmpty()
                       where item == null
                       select tnew).ToList();

            CommunList = (from tnew in iNewList.ToList()
                          join toriginal in iOriginalList.ToList()
                          on iNewProperty(tnew)
                          equals iOriginalProperty(toriginal) into gj
                          from item in gj.DefaultIfEmpty()
                          where item != null
                          select tnew).ToList();

            CommunPairList = (from tnew in iNewList.ToList()
                              join toriginal in iOriginalList.ToList()
                              on iNewProperty(tnew)
                              equals iOriginalProperty(toriginal) into gj
                              from item in gj.DefaultIfEmpty()
                              where item != null
                              select new KeyValuePair<TOriginal, TNew>(item, tnew)).ToList();

            RemovedList = (from toriginal in iOriginalList.ToList()
                           join tnew in iNewList.ToList()
                           on iOriginalProperty(toriginal)
                           equals iNewProperty(tnew) into gj
                           from item in gj.DefaultIfEmpty()
                           where item == null
                           select toriginal).ToList();
            return;

    }

    #region PROPRIETES

    public List<TNew> NewList { get; private set; }
    public List<TOriginal> RemovedList { get; private set; }
    public List<TNew> CommunList { get; private set; }
    /// <summary>
    /// Obtient la liste de pair avec l'original en key et le nouveau en value
    /// </summary>
    public List<KeyValuePair<TOriginal,TNew>> CommunPairList { get; private set; }

    #endregion

}

```

use:

```
List<Tuple<string, string>> list1 = new List<Tuple<string, string>>();
        List<Tuple<string, string>> list2 = new List<Tuple<string, string>>();

        list1.Add(new Tuple<string, string>("AA", "zefzef"));
        list1.Add(new Tuple<string, string>("A1", "iulyu"));

        list2.Add(new Tuple<string, string>("Abb", "szefez"));
        list2.Add(new Tuple<string, string>("A1", "zevzez"));

        ListComparator<Tuple<string, string>, Tuple<string, string>> comp = new ListComparator<Tuple<string, string>, Tuple<string, string>>(list1, x => x.Item1, list2, a => a.Item1);

```

OUTPUT :

1 commun, 1 removed, 1 new

thanks