jeudi 20 juillet 2017

How to properly use cache to optimize performance when using Reflection?

This is my first question on StackOverflow!

I'm working on a library which defines a simple class like below:

public class Delta<T> : Dictionary<string, object> where T : class, new()
{   
    private PropertyInfo[] properties;

    public Delta() : base()
    {
        properties = typeof(T).GetProperties();
    }
}

The main project (which can be WinForms, ConsoleApp, Web API, MVC) will use this library like that:

public static void main()
{
    var mClass = new Delta<MyClass();
    check(mClass);
}

public class MyClass {
   public string Prop1 { get; set; }
   public string Prop2 { get; set; }
}

private static void check(Delta<MyClass> delta)
{

}

As you can see, the Delta class obtains the properties informations of the T class (MyClass in this case). The methods of Delta class that I have to implement will use only the SetValue and GetValue methods of the PropertyInfo class. This operation (getting the properties of the T class) may be executed many times for the same T class and other classes depending on the number of created instances. For example:

var mycollection = new List<Delta<MyClass>>();
for (int i = 0; i < length; i++)
{
    mycollection.Add(new Delta<MyClass>());
}

var mycollection2 = new List<Delta<MyClass2>>();
for (int i = 0; i < length; i++)
{
    mycollection2.Add(new Delta<MyClass2>());
}

So I added a cache system like this:

internal static class DeltaCache
{
    public static Dictionary<string, PropertyInfo[]> entityProperties = new Dictionary<string, PropertyInfo[]>();

    public static void Add(string key, PropertyInfo[] values)
    {
        entityProperties.Add(key, values);
    }
}

Now, the Delta class check if exists an entry on the entityProperties dictionary before getting the properties from the T type.

public class Delta<T> : Dictionary<string, object> where T : class, new()
{
    private PropertyInfo[] properties;

    public Delta() : base()
    {
        var type = typeof(T);
        if (DeltaCache.entityProperties.ContainsKey(type.FullName))
        {
            properties = DeltaCache.entityProperties[type.FullName];
        }
        else
        {
            properties = type.GetProperties();
        }
    }
}

Now I have two choices:

  1. If the entity's properties are not cached I add them to the cache;
  2. On application start (for example in the Application_Start event of the Global.asax file for an ASP.NET Website) I find all usages of Delta<T> and I add the properties of each T class to the cache.

The cons of the first point is that the GetProperties method is executed once for class and I have to do some checks. The cons of the second point is (I think) that it may take a little time to get all references to T. However it's only on startup which may not be a problem. Could someone show me how should be the code to implement the second solution?

Also, I have some doubts:

  1. Should I consider caching the SetValue and GetValue methods instead of the PropertyInfo object? (Maybe using delegates or Actions)
  2. Are there better methods to optimize this code that I'm not considering?
  3. Should I worry about the size of the "cache"?
  4. Based on performance savings, is it worth implementing all this code?

Thank you!





Aucun commentaire:

Enregistrer un commentaire