mardi 25 avril 2023

Why below function is not being optimized by using delegate?

I have below function to send the log. And I used to have a reflection approach.(The commented code inside the function). I would like to optimize the reflection, after some investigation online, I ended with below solution and it still took me the same time. (20 secs for processing 100k log records). Can anyone help/guide me why?

public static class JsonHelper
{
    private static readonly ConcurrentDictionary<Type, Func<object, object>> _delegateCache = 
        new ConcurrentDictionary<Type, Func<object, object>>();

    private static readonly ConcurrentDictionary<Type, PropertyInfo[]> _propertyCache =
        new ConcurrentDictionary<Type, PropertyInfo[]>();

    public static string ToJson(this object obj)
    {
        return JsonConvert.SerializeObject(obj);
    }

    /// <summary>
    /// Create LogEventInfo object. 
    /// </summary>
    /// <param name="data"></param>
    /// <param name="message"></param>
    /// <param name="ex"></param>
    /// <returns></returns>
    public static LogEventInfo ToLogEventInfo(this ILogItem data, string message, Exception ex = null)
    {
        var eventInfo = new LogEventInfo();

        if (ex != null)
            eventInfo.Exception = ex;

        if (data != null)
        {
            data.EventMessage = message;
            data.LogTime = TimeZoneInfo.ConvertTime(DateTime.Now, TimeZoneInfo.Utc);
            data.LogId = Guid.NewGuid();


            //var properties = data.GetType().GetProperties();
            //foreach (var property in properties)
            //{
            //    eventInfo.Properties[property.Name] = property.GetValue(data, null);
            //}

            //Cache the delegate with expression tree.
            if (!_propertyCache.TryGetValue(data.GetType(), out var propertyInfo))
            {
                var properties = data.GetType().GetProperties();
                var delegateProperties = new Func<object, object>[properties.Length];

                for (int i = 0; i < properties.Length; i++)
                {
                    delegateProperties[i] = GenerateGetterLambda(properties[i]);

                    var propertyName = properties[i].Name;
                    var propertyValue = delegateProperties[i].Invoke(data);
                    _delegateCache.TryAdd(properties[i].PropertyType, delegateProperties[i]);

                    eventInfo.Properties[propertyName] = propertyValue;
                }
                _propertyCache.TryAdd(data.GetType(), properties);
            }
            else
            {
                var properties = propertyInfo;

                var length = properties.Length;
                for (var i= 0; i < length; i++)
                {
                    if (_delegateCache.TryGetValue(properties[i].PropertyType, out var propertyDelegate))
                    {
                        eventInfo.Properties[properties[i].Name] = propertyDelegate.Invoke(data);
                    }
                }
            }
        }
        else
        {
            if (!string.IsNullOrEmpty(message))
                eventInfo.Message = message;
        }

        return eventInfo;
    }

    /// <summary>
    /// Combined with expression tree to futher improve the performance.
    /// </summary>
    /// <param name="property"></param>
    /// <returns></returns>
    private static Func<object, object> GenerateGetterLambda(PropertyInfo property)
    {
        var expParameter = Expression.Parameter(typeof(object), "instance");
        var expInstance = Expression.TypeAs(expParameter, property.DeclaringType);
        var expProperty = Expression.Property(expInstance, property);
        var expPropertyObj = Expression.Convert(expProperty, typeof(object));
        return Expression.Lambda<Func<object, object>>(expPropertyObj, expParameter).Compile();
    }
}




Aucun commentaire:

Enregistrer un commentaire