0

I'm attempting write a generic method to do memberwise compare on user defined objects which potentially (almost always) have several levels of nesting. I'm working off of the example found here with one little twist; if the property cannot be compared with the equality operator (those in the pTypes array), then I want to make a recursive call passing in the current properties. The code I have will not compile, I've tried various syntax in the recursive call and I'm simply wondering what is the correct syntax? Or can you do this at all?

Here is my method as of now;

    public static string[] MemberWiseCompare<T>(T act, T exp) where T : ICommonObject
    {
        List<string> errors = new List<string>();

        if (act != null && exp != null)
        {
            Type[] pTypes = { typeof(int), typeof(bool), typeof(string), typeof(float), typeof(double), typeof(DateTime) };
            Type type = typeof(T);
            foreach (PropertyInfo pi in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
            {
                if (pTypes.Contains(pi.PropertyType))
                {
                    if (type.GetProperty(pi.Name).GetValue(act, null) != type.GetProperty(pi.Name).GetValue(exp, null))
                    {
                        errors.Add(pi.Name);
                    }
                }
                else
                {
                    string[] innerErrors = MemberWiseCompare<pi.PropertyType>(pi.GetValue(act, null), pi.GetValue(exp, null));
                }
            }
        }
        return null;
    }

Of course there are other parts of the method which I've yet to implement (aggregating the errors at the bottom of the function and returning something other than null) but for the time being I'm only concerned with getting the recursive MemberWiseCompare to work. From there I can figure out the rest. I think I have some problem understanding what the compiler is taking away from the type I specify for the generic ( ie pi.PropertyType ). I figured that would work because it's providing the type we'll be using in the generic call. I'm also anticipating some problems with it boxing my values so that GetValue returns an object rather than the more specific type.

EDIT: The compiler error is the good old "best overloaded method has some invalid args"

Community
  • 1
  • 1
evanmcdonnal
  • 46,131
  • 16
  • 104
  • 115

2 Answers2

1

It does not compile because a generic argument value has to be available at compile time. In the inner call to the MemberWiseCompare you are trying to pass to it a value only available at runtime.

The funny thing is that you do not really need it to be generic - you use reflection to explore the type and you do not need the actual type of the arguments compile time. Just give both act and exp the iCommonObject type and the compilation will go through

mfeingold
  • 7,094
  • 4
  • 37
  • 43
  • Upvoted because this is essentially right. But none of the types in `pTypes` implement `ICommonObject`, so I'm not sure what ICommonObject is even supposed to be doing here...? Seems like `object` is all that is needed or will work. – Dominic P May 16 '13 at 21:26
  • @DominicP - you are correct, sir. As per the code sample in the posting object should suffice here – mfeingold May 16 '13 at 21:42
  • @DominicP ICommonObject is an interface that all of the objects we've defined implement. The objects in pTypes are the "primitive types" which can be compared with the equality operator. The contains check is to ensure that the current property overloads == or has native support for it. If it doesn't then I know it's one of our objects and so I need to call `MemberWiseCompare` once again with that object so it's "primitive types" can be compared. – evanmcdonnal May 16 '13 at 21:42
  • Ah, I see. Right, I misread the code. If you definitely want yo use generics, though, you'd need at a minimum to cast to ICommonObject in the recursive call. My main point was that typing the parameters as object would seem to suffice, but your point is well-taken. – Dominic P May 16 '13 at 22:40
0

This should work:

string[] innerErrors = MemberWiseCompare(pi.GetValue(act, null), pi.GetValue(exp, null));

Rukshan Perera
  • 150
  • 2
  • 9