-1

I have to do a comparison of 2 lists. The problem is that I don't know of what type the field inside the list are, they can be int, string, decimal, enums or even other objects.

I will know the type only on runtime. I was thinking of creating a list of object and cast them to object the problem is that let's say I have a List<int> and I'm trying to cast it to object it fails.

Another problem is that I know there is a list only on runtime. so on runtime I need to transform the variable of type object to a list.

How can I cast that object to List and how can I cast it to let's say list of objects?

Update:

I have and object and by reflection I'm getting the the property of it with

var oldProperty = property.GetValue(old);
var newProperty = property.GetValue(new);

Once I have the properties values and I can see it's a list I will need to compare those 2. Let's say oldProperty is of type List I've tried to do something like:

var myOldList = (List<object>)oldProperty;

If the cast fails with

Unable to cast object of type 'System.Collections.Generic.List`1[System.Int32]' to type 'System.Collections.Generic.List`1[System.Object]'

Here you have a look of the function i;m trying to create. Please don't mind of null objects(is not in the scope)

 public void SetDifference(object first, object second)
    {
        var properties = first.GetType().GetProperties();
        foreach (PropertyInfo property in properties)
        {
            var oldValue = property.GetValue(first);
            var newValue = property.GetValue(second);
            if (Convert.GetTypeCode(newValue) != TypeCode.Object)
            {
                if (!oldValue.Equals(newValue))
                {
                    result.AddDifference(new PrimitiveComparison()
                    {
                        BeforeValue = oldValue.ToString(),
                        AfterValue = newValue.ToString(),
                        PropertyName = property.Name
                    });
                }
            }
            else
            {
                if (property.PropertyType.Name.Contains("List"))
                {
                    // here fails with the error from above
                    var oldList = (List<object>)oldValue; 
                    var newList = (List<object>)newValue;
                    if (oldList.Count != newList.Count)
                    {
                        result.AddDifference(new PrimitiveComparison()
                        {
                            BeforeValue = oldList.Count.ToString(),
                            AfterValue = newList.Count.ToString(),
                            PropertyName = property.Name + "Count"
                        });
                    }
                    // add the list differences
                    result.AddDifference(SetListDifference(oldList, newList);
                }
                else
                {
                    var diffrence = SetDifference(oldValue, newValue);
                    if (!diffrence.areEqual)
                    {
                        result.AddDifference(diffrence);
                    }
                }

            }
        }


}
Radu
  • 1,047
  • 12
  • 34
  • 3
    It would be a lot easier to help you if you'd provide a [mcve] rather than just a description. Also, focus on a single problem at a time - it sounds like you're trying to ask two different questions here. – Jon Skeet Dec 07 '17 at 09:04
  • @JonSkeet okay i'm trying to edit it now. Just a sec – Radu Dec 07 '17 at 09:05
  • @Liam sound like that but I need more procesing on that. I need a bit more of a comparison that what is done for list on https://www.nuget.org/packages/CompareNETObjects/ and I was instructed to create our own library – Radu Dec 07 '17 at 09:10
  • I don't understand that comment? – Liam Dec 07 '17 at 09:11
  • 1
    @Liam SequenceEqual requires you to know type of list at compile time, but OP doesn't know that (has just two objects or maybe IEnumerables of unknown type). – Evk Dec 07 '17 at 09:12
  • @JonSkeet please see my update hope it helps :) – Radu Dec 07 '17 at 09:16
  • 1
    No, that's still not a [mcve]. – Jon Skeet Dec 07 '17 at 09:17
  • So it sounds like your trying to do some kind of "deep" object comparison using reflection? – Liam Dec 07 '17 at 09:18
  • 1
    @Liam yes that's exactly what I'm trying but the problem is that I can't do a validation for list – Radu Dec 07 '17 at 09:20
  • You can cast both values to `IList` (non-generic) and compare those – Evk Dec 07 '17 at 09:23
  • 1
    lets forget programming for a while. do you really can compare two lists which are one has collect apples another bananas. Advice:simply "do not compare" or question really weak... another solution first : could you please implements your list member by IComparable or second: you will need many (!) IEqualityComparer implementation for every types of member of your lists. – Nuri YILMAZ Dec 07 '17 at 09:27
  • @NuriYILMAZ If you think that this si not about programming it means you did not understood the problem – Radu Dec 07 '17 at 09:32
  • if you are trying to compare two list of diffrent type than its not going to work – Pranay Rana Dec 07 '17 at 09:45
  • @PranayRana the oldList and new ist from the above exemple have the same type by I do not know how how to compare them. I can't go with a swich on each of them. I will try your thing – Radu Dec 07 '17 at 09:48
  • @Radu - you can check my udpated answer you need to use Except method to find list equal or not – Pranay Rana Dec 07 '17 at 09:56

2 Answers2

2

You can just cast your two values to IList and compare them, for example like this:

static bool AreEqual(IList first, IList second) {
    if (first.Count != second.Count)
        return false;
    for (int i = 0; i < first.Count; i++) {
        if (!object.Equals(first[i], second[i]))
            return false;
    }
    return true;
}
Evk
  • 98,527
  • 8
  • 141
  • 191
1

once you do conversion of you list than you can check both the list have same element or not by using except method of linq, to find both are equal or not

double[] numbers1 = { 2.0, 2.1, 2.2, 2.3, 2.4, 2.5 };
double[] numbers2 = { 2.0, 2.1, 2.2, 2.3, 2.4, 2.5 };

IEnumerable<double> onlyInFirstSet = numbers1.Except(numbers2);
if(onlyInFirstSet.Count() ==0)
 Console.WriteLine("equal");

for primitive type this works fine but for user defined type you need compare implementation.

Check this blog post for comparing list of two different type : Difference between list of user defined types


If you are aware that is going to be IEnumerable type than you can try

 List<object> objlst = (value as IEnumerable<object>).Cast<object>
    ().ToList()

you can try like this

Type t = typeof(obj);

if (t == typeof(List<int>)) {
    var lst= (List<int>)obj;

} else if (t == typeof(List<string>)) {
    var lst = (List<string>)obj;
} else if (t == typeof(List<decimal>)) {
    var lst = (List<decimal>)obj;
} 
else if (t == typeof(List<EnumName>)) {
    var lst = (List<EnumName>)obj;
}
Pranay Rana
  • 175,020
  • 35
  • 237
  • 263
  • what about decimal, enums, etc. as stated in the question? – Liam Dec 07 '17 at 09:07
  • @Liam - you can add more if condtion right ,,, if you want i can write that also... – Pranay Rana Dec 07 '17 at 09:08
  • 1
    Or he can just use [SequenceEqual](https://stackoverflow.com/a/43505/542251) without any casting, if else, etc., – Liam Dec 07 '17 at 09:09
  • @Liam-- but for that also you need two IEnumerable sequence , you can add you answer also if you think that is the way – Pranay Rana Dec 07 '17 at 09:11
  • *comparison of 2 lists* List are enumerables? – Liam Dec 07 '17 at 09:12
  • @Liam - check here Enumerable.SequenceEqual Method (IEnumerable, IEnumerable, IEqualityComparer) as per systax you need comparer of type also ...https://msdn.microsoft.com/en-us/library/bb342073.aspx..if you dont know type of object how you are going do that – Pranay Rana Dec 07 '17 at 09:14
  • @Liam - before putting -1 better to check solution and things you are providing ...i am not saying i am correct based on question i provided answer that may be wrong ... – Pranay Rana Dec 07 '17 at 09:16
  • @PranayRana I have tested what you've said and (value as IEnumerable) works as expected for any object or string but returns null for int, long decimal and primitives so the .Cast will fail with null pointer exception – Radu Dec 07 '17 at 10:32
  • @Radu - for primitive type i suggest second option...you can try that ... – Pranay Rana Dec 07 '17 at 10:58
  • @Radu - I suggest you can try out Evk opt also that might fit in your requirement – Pranay Rana Dec 07 '17 at 11:05
  • @PranayRana both ot the answers helped me a lot. I will give you the answer because your's helped me a bit more. Both of them are very good ones. – Radu Dec 07 '17 at 15:08