1

Assume i have a class like this below

class Student
{
public int ID { get; set; }

public string Name { get; set; }
}

Just with 10 more properties. I want to loop through these properties. I can do it through reflection, which will have a performance cost. Is serializing it using Newtonsoft JSON and looping through it better?


Edit: The reason i want to do this is there are many classes like this. Each of these classes also has a Ienumerable object as below

public bool Validation
{
public string PropName { get; set; }
public bool IsRequired { get; set; }
public int? MaxLength { get; set; }
public int? MinLength { get; set; }

public void Validate(object propValue)
{... }
}

I want to loop through each property in student class, take values and supply it to validate method. But i don't want to use reflection. I am not sure if it is even possible. Let me know if u have any thoughts.

  • Why not just try it out? – MakePeaceGreatAgain Jun 18 '20 at 13:46
  • 4
    You would have to measure it. Considering that serializing it will use reflection, I seriously doubt the total cost will be lower. – Lasse V. Karlsen Jun 18 '20 at 13:46
  • 1
    What do you want to do in the loop? – Guru Stron Jun 18 '20 at 13:48
  • 2
    Why do you want to loop the properties? Seems x-y to me. – Fildor Jun 18 '20 at 13:48
  • 2
    Serializing comes with a cost too, likely using reflection as well, and then parsing the json also has a cost. Is this really a hotspot in your program? Consider writing the code in a clear usable manner instead. If that becomes a hotspot on profiling then optimize as appropriate against the baseline you already have written. – Retired Ninja Jun 18 '20 at 13:49
  • I have edited this to add the 'Why'. Please note that existing code can't be changed too much. Any small tweaks to existing code is possible. There are too many reasons for this to give here. – krishnaprasad parthasarathy Jun 18 '20 at 14:18
  • Why don't you want to use reflection? – Joshua Robinson Jun 18 '20 at 14:26
  • Yes it's possible to use Newtonsoft for this, but it might not be worth the trouble. It is very easy to loop through the properties of a class and get their values after all, see [How to loop through all the properties of a class?](https://stackoverflow.com/q/531384). Are you going to be validating *many* `Student` objects? Are you sure you have a performance problem? – dbc Jun 18 '20 at 15:50

1 Answers1

3

If you are disturbed by performance hit of the reflection you can "cache" it using generic static classes and private static fields in them (which are not shared) and some compilation magic using expression trees. For example (modified your code to make it compile):

public static class Validator<T>
{
    private static readonly Dictionary<string, Func<T, object>> propGetters;
    static Validator()
    {
        propGetters = 
        typeof(T)
            .GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(p => p.GetGetMethod() != null)
            .ToDictionary(p => p.Name, p =>
            {
                var par = Expression.Parameter(typeof(T));
                var access = Expression.Property(par, p);
                var lambda = Expression.Lambda<Func<T, object>>(Expression.Convert(access, typeof(object)), par);
                return lambda.Compile();
            });
    }   
    
    public static bool Validate(T c, IEnumerable<Validation> v)
    {
        return v.All(v => v.Validate(propGetters[v.PropName](c)));
    }
}

class Student
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class Validation
{
    public string PropName { get; set; }
    public bool IsRequired { get; set; }
    public int? MaxLength { get; set; }
    public int? MinLength { get; set; }

    public bool Validate(object propValue)
    { return false; }
}

Which can be used like this:

var x = new Student();
var validations = new[]
{
    new Validation
    {
        PropName = "Name",
        IsRequired = true,
        MinLength = 1,
        MaxLength = 10
    }
};
Validator<Student>.Validate(x, validations);

This code can be improved(for example if IEnumerable<Validation> is collection on the class itself you can move code getting it to another static property and remove corresponding parameter of Validator.Validate)

Guru Stron
  • 102,774
  • 10
  • 95
  • 132
  • thanks @Guru. This is solves the performance problem of reflection to a large extent – krishnaprasad parthasarathy Jun 19 '20 at 10:27
  • @krishnaprasadparthasarathy was glad to help! – Guru Stron Jun 19 '20 at 12:26
  • @guru-stronton - Just one question - There are around 200 student like classes and with each one having ~ 15 properties. So total of 3000 PropGetter Funcs. Will this have a big performance impact? I know there will have to be compromises some place. but i was just wanted to know the impact this would have. – krishnaprasad parthasarathy Jun 20 '20 at 09:47
  • @krishnaprasadparthasarathy you should benchmark your concrete case. Last time I checked compiled expression for getters were working with approximately the same speed as ordinary ones(though it can depend on framework/compiler version), also you will have some overhead on dictionary access, but in my experience both this factors never were bottleneck in my app. Also you will have a little more memory needed to store 3000 PropGetter Funcs but it will constant(cause "caching", if you do not create classes dynamically) and less then dynamic string(json) manipulation/reflection. – Guru Stron Jun 20 '20 at 12:59
  • @guru-stronton - Thanks. I will benchmark it n see. – krishnaprasad parthasarathy Jun 22 '20 at 09:04