4

I need to find the longest value from a list of objects like this...

var longestValue = list.Max(x => x.Name);

The problem is that I can not access it directly like this but this need to be made in a loop. Here is what I have so far..

        public static void SetPropertyValue(this object obj, string propName, object value)
    {
        obj.GetType().GetProperty(propName).SetValue(obj, value, null);
    }


        var user = new User();

        var list = new List<User>
        {
            new Svedea {Name = "Steve", Car = "Volkswagen"},
            new Svedea {Name = "Denice Longhorn", Car = "Tesla"},
            new Svedea {Name = "Rebecca", Car = "Ford"},
            new Svedea {Name = "Mike O", Car = "Mercedes-Benz"}
        };

        var properties = user.GetType().GetProperties();
        var propList = properties.Select(pi => pi.Name).ToList();

        var newUser = new User();

        foreach (var row in propList)
        {
            // Here I need to find the longest value from the list above like this...
            // var longestValue = list.Max(x => x.row); // This is obviously not correct but I need to find this value needs to be found dynamically

            var longestValue = list.Max(x => x.row);
            newUser.SetPropertyValue(row, longestValue);

        }
MTplus
  • 2,077
  • 4
  • 34
  • 51
  • Could you try to clarify your requirements? It's not clear why you're using reflection, or what you'd expect the results to be. What would you expect to happen for non-string properties? What happens if there are multiple values with the same length? – Jon Skeet Apr 11 '18 at 07:25
  • The purpose is to create a new "User" that has the longest values from each propery. If there is more than one value I will only use the first one. – MTplus Apr 11 '18 at 07:29
  • so `"Denice Longhorn"` and `"Mercedes-Benz"` ? – TheGeneral Apr 11 '18 at 07:31
  • Yes thats correct – MTplus Apr 11 '18 at 07:32
  • So why were you using Reflection? will the answers supplied suit your needs? – TheGeneral Apr 11 '18 at 07:36
  • The answers supplied does not work since they access by the propertyName directly the User class can vary, it can be more properties added and I want to have a generic way to create a single User object that contains the longest values for each property – MTplus Apr 11 '18 at 07:39
  • And what about non-string values? – Jon Skeet Apr 11 '18 at 07:52
  • There is currently only string values.. – MTplus Apr 11 '18 at 07:54

2 Answers2

0

Use LINQ OrderByDescending to sort your list by the longest value of Name and the longest value of Car. Then you can create a new User longestUser that has the longest values of Name and Car:

var longestName = list.OrderByDescending(x => x.Name.Length).First().Name;
var longestCar = list.OrderByDescending(x => x.Car.Length).First().Car;
var longestUser = new User() { Name = longestName, Car = longestCar };

longestUser:

Name = "Denice Longhorn"

Car = "Mercedes-Benz"

EDIT:

I have modified my solution above so that you can access the property names with string values :

var longestNameUser = list.OrderByDescending(x => x.GetType().GetProperty("Name").GetValue(x, null).ToString().Length).First();
var longestName = longestNameUser.GetType().GetProperty("Name").GetValue(longestNameUser, null);

var longestCarUser = list.OrderByDescending(x => x.GetType().GetProperty("Car").GetValue(x, null).ToString().Length).First();
var longestCar = longestCarUser.GetType().GetProperty("Car").GetValue(longestCarUser, null);

var newUser = new User();
PropertyInfo propertyInfo;

propertyInfo = newUser.GetType().GetProperty("Name");
propertyInfo.SetValue(newUser, Convert.ChangeType(longestName, propertyInfo.PropertyType), null);

propertyInfo = newUser.GetType().GetProperty("Car");
propertyInfo.SetValue(newUser, Convert.ChangeType(longestCar, propertyInfo.PropertyType), null);

Your modified for loop :

var newUser = new User();
PropertyInfo propertyInfo;

foreach (var row in propList)
{
    var longestValueUser = list.OrderByDescending(x => x.GetType().GetProperty(row).GetValue(x, null).ToString().Length).First();
    var longestValue = longestValueUser.GetType().GetProperty(row).GetValue(longestValueUser, null);
    propertyInfo = newUser.GetType().GetProperty(row);
    propertyInfo.SetValue(newUser, Convert.ChangeType(longestValue, propertyInfo.PropertyType), null);
}
Slaven Tojić
  • 2,945
  • 2
  • 14
  • 33
0

You can do something like this with a mixture of generics and reflection

Exmaple

public static T CreateType<T>(List<T> list) where T : new ()
{
   var obj = new T();

   var type = typeof(T);
   var properties = type.GetProperties();

   foreach (var prop in properties)
   {
      var value = list.Select(x => x.GetType()
                                    .GetProperties()
                                    .First(y => y == prop)
                                    .GetValue(x) as string)
                      .OrderByDescending(x => x.Length)
                      .First();

      var propInstance = obj.GetType()
                            .GetProperties()
                            .First(x => x == prop);

      propInstance.SetValue(obj, value);
   }

   return obj;
}

Usage

var someList = new List<SomeClass>()
                  {
                     new SomeClass()
                        {
                           Name = "asd",
                           Car = "sdfsdf"
                        },
                     new SomeClass()
                        {
                           Name = "dfgfdg",
                           Car = "dfgdf"
                        }
                  };


var SomeClass = CreateType(someList);

Output

some value 1 longer, Some value 2 longer

Full demo here

TheGeneral
  • 79,002
  • 9
  • 103
  • 141