Vignesh G
Vignesh G

Reputation: 67

Reflection with Delegates

I'm using reflection to compare two list of objects(of same type) and collecting the list of properties which have different values. I may iterate through lots of object list to compare which ended in performance lag. I came to know about using delegates in the reflection so we can bypass the .GetValue(obj, null) which is taking time. The types of my class properties is wide. It can be string, int and enum. The available solutions are not working out for me. Thanks for your help.

The code I'm using to compare the 2 objects of same type

public List<string> Compare<T>(object A, object B)
{
                var type = typeof(T);
                var allProperties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);

                List<string> unequalProperties =
                    (
                        from pi in allProperties 
                        let AValue = type.GetProperty(pi.Name).GetValue(A, null)
                        let BValue = type.GetProperty(pi.Name).GetValue(B, null)
                        where AValue != BValue && (AValue == null || !AValue.Equals(BValue))
                        select pi.Name
                    ).ToList();
                return unequalProperties;
}

The two .GetValue(A/B, null) is producing the lag which i want to skip using delegates.

Upvotes: 0

Views: 459

Answers (1)

Charlieface
Charlieface

Reputation: 71144

You can cache the getter delegates in a static field, by putting your code into a generic class.

You can then cache the properties themselves using a two-level class hierarchy using some more generics.

public List<string> Compare<T>(T A, T B)
{
    return GenericComparer<T>.Compare(A, B);
}

abstract class PropertyCompareBase<T>
{
    public string Name;
    public abstract bool CompareProperty(T A, T B);
}

class PropertyCompare<T, TProperty> : PropertyCompareBase<T>
{
    Func<T, TProperty> Getter;

    public PropertyCompare(PropertyInfo prop)
    {
        Name = prop.Name;
        Getter = (Func<T, TProperty>)prop.GetMethod.CreateDelegate(typeof(Func<T, TProperty>));
    }

    public override bool CompareProperty(T A, T B)
    {
        return EqualityComparer<TProperty>.Default.Equals(Getter(A), Getter(B));
    }
}

static class GenericComparer<T>
{
    static List<PropertyCompareBase<T>> properties = typeof(T)
        .GetProperties(BindingFlags.Public | BindingFlags.Instance)
        .Where(p => p.GetIndexParameters().Length == 0)
        .Select(p => (PropertyCompareBase<T>)Activator.CreateInstance(
                         typeof(PropertyCompare<,>)
                         .MakeGenericType(typeof(T), p.PropertyType),
                        p))
        .ToList();

    static public List<string> Compare(T A, T B)
    {
        List<string> unequalProperties =
            properties.Where(p => !p.CompareProperty(A, B))
                      .Select(p => p.Name)
                      .ToList();
        return unequalProperties;
    }
}

dotnetfiddle

Upvotes: 2

Related Questions