using System.Collections.Generic;
public Holiday(DateTime hDate, string descr, DateTime? rDate = null)
public DateTime HolidayDate { get; set; }
public string Description { get; set; }
public DateTime? ReplacementDate { get; set; }
public static void Main(string[] args)
var list = new List<Holiday>()
new Holiday(new DateTime(2016,1,1),"NEW YEAR 2016"),
new Holiday(new DateTime(2016,3,27),"EASTER MONDAY 2016", new DateTime(2016,3,28)),
new Holiday(new DateTime(2016,12,25),"CHRISTMAS DAY 2016", new DateTime(2016,12,26)),
new Holiday(new DateTime(2017,1,1),"NEW YEAR 2017", new DateTime(2017,1,2)),
new Holiday(new DateTime(2017,4,17),"EASTER MONDAY 2017"),
new Holiday(new DateTime(2017,12,25),"CHRISTMAS DAY 2017"),
new Holiday(new DateTime(2018,1,1),"NEW YEAR 2018"),
new Holiday(new DateTime(2018,1,1),"DUPLICATE 1"),
new Holiday(new DateTime(2018,1,2),"DUPLICATE 2", new DateTime(2016,1,1)),
new Holiday(new DateTime(2018,1,3),"DUPLICATE 3", new DateTime(2017,1,2)),
new Holiday(new DateTime(2018,1,4),"DUPLICATE 4", new DateTime(2018,1,4)),
var result = list.GetDuplicates<Holiday, DateTime>().ToList();
Console.WriteLine(result.Count);
Console.WriteLine(string.Join(", ", result.Select(q => q.Reference.Description)));
var values = result.Select(r => r.Value).Distinct();
Console.WriteLine(string.Join("\r\n", values.Select(q => q)));
public class MainObject<TRef, TProp> where TProp : struct
public TRef Reference { get; set; }
public TProp? Value { get; set; }
public bool SelfDuplicate { get; set; }
public static class Extensions
public static IEnumerable<MainObject<TIn, TProp>> GetDuplicates<TIn, TProp>(this IEnumerable<TIn> @this) where TProp : struct
var props = type.GetProperties(BindingFlags.Instance | BindingFlags.Public).Where(prop => prop.PropertyType == typeof(TProp) || prop.PropertyType == typeof(TProp?)).ToList();
var list = @this as IList<TIn> ?? @this.ToList();
var duplicates = new List<MainObject<TIn, TProp>>();
foreach (var item1 in list)
var isSelfDupe = item1.IsDuplicate<TIn, TProp>(props);
duplicates.Add(new MainObject<TIn, TProp>
Value = (TProp?)isSelfDupe.Property1.GetValue(item1)
foreach (var item2 in list)
if (ReferenceEquals(item1, item2)) continue;
var isDuplicate = item1.IsDuplicate<TIn, TProp>(item2, props);
duplicates.Add(new MainObject<TIn, TProp>
Value = (TProp?)isDuplicate.Property1.GetValue(item1)
return duplicates.Distinct().ToList();
private static IsDuplicateResult<TIn> IsDuplicate<TIn, TProp>(this TIn obj1, IEnumerable<PropertyInfo> props) where TProp : struct
var propList = props as IList<PropertyInfo> ?? props.ToList();
var valueList = propList.Select(prop => prop.GetValue(obj1)).ToList();
foreach (var p1 in propList)
foreach (var p2 in propList)
if (ReferenceEquals(p1, p2)) continue;
if (EqualityComparer<TProp?>.Default.Equals((TProp?)p1.GetValue(obj1), (TProp?)p2.GetValue(obj1)))
return new IsDuplicateResult<TIn> { IsDupe = true, Reference = obj1, Property1 = p1, Property2 = p2 };
return new IsDuplicateResult<TIn> { IsDupe = false };
private static IsDuplicateResult<TIn> IsDuplicate<TIn, TProp>(this TIn obj1, TIn obj2, IEnumerable<PropertyInfo> props) where TProp : struct
var propList = props as IList<PropertyInfo> ?? props.ToList();
var dict1 = propList.ToDictionary(prop => prop, prop => prop.GetValue(obj1));
var dict2 = propList.ToDictionary(prop => prop, prop => prop.GetValue(obj2));
foreach (var k1 in dict1.Keys)
foreach (var k2 in dict2.Keys)
if (dict1[k1] == null || dict2[k2] == null) continue;
if (EqualityComparer<TProp?>.Default.Equals((TProp?)dict1[k1], (TProp?)dict2[k2]))
return new IsDuplicateResult<TIn> { IsDupe = true, Reference = obj1, Property1 = k1, Property2 = k2 };
return new IsDuplicateResult<TIn> { IsDupe = false };
private class IsDuplicateResult<TIn>
public bool IsDupe { get; set; }
public TIn Reference { get; set; }
public PropertyInfo Property1 { get; set; }
public PropertyInfo Property2 { get; set; }