Reflection is a great tool when it comes to handling the information at runtime. I found this solution below to be suitable in one of my applications because I wanted something that I could easily adapt.
The implementation of the method below looks for both public and private fields and properties.
- namespace MyNamespace
- {
- static class Extensions
- {
- public static IEnumerable<T> DistinctBy<T, Tkey>(this IEnumerable<T> @this, string binding)
- {
- string[] PropertyNames = binding.Split('.');
- IList<Tkey> PropertyValues = new List<Tkey>();
- IList<T> DistinctList = new List<T>();
-
- foreach (var item in @this)
- {
-
- object Key = item;
- foreach (var Property in PropertyNames)
- {
- Type keyType = Key.GetType();
-
- FieldInfo fieldInfo = keyType.GetField(Property, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
- PropertyInfo propertyInfo = keyType.GetProperty(Property, BindingFlags.Public | BindingFlags.NonPublic |BindingFlags.Instance);
- if (propertyInfo != null)
- {
- Key = propertyInfo.GetValue(Key);
- }
- else if (fieldInfo != null)
- {
- Key = fieldInfo.GetValue(Key);
- }
- else {
- Key = null;
- }
- }
- if (Key == null) {
- DistinctList.Add(item);
- }
- else if (PropertyValues.Where(x => x.Equals(Key)).Count() == 0)
- {
- PropertyValues.Add((Tkey)Key);
- DistinctList.Add(item);
- }
- }
- return DistinctList;
- }
- }
Let’s create a product class that has a Price. We aim to easily create a list with unique “parameters” that will be defined in a string.
- class Price
- {
- public double Value { get; set; }
- }
- class Product
- {
- public string Name { get; set; }
- public Price Price { get; set; }
- private int NoPrice;
- }
- class Program
- {
- static void Main(string[] args)
- {
- List<Product> Products = new List<Product>
- {
- new Product{ Name = "Product1", Price = new Price{ Value = 100} },
- new Product{ Name = "Product2", Price = new Price{ Value = 100} },
- new Product{ Name = "Product3", Price = new Price{ Value = 200} }
- };
-
- var DistinctProducts1 = Products.DistinctBy<Product, int>("NoPrice");
-
-
- var DistinctProducts2 = Products.DistinctBy<Product, int>("NoPrice.Test");
-
-
- var DistinctProducts3 = Products.DistinctBy<Product, int>("Price.Value");
- }
- }
- }