vendredi 14 octobre 2022

Expression API - No increase in performance

I posted a question yesterday about this and the answer I received worked somewhat, however it is not enough. I'm using reflection to extract attribute data from my DTO classes, and these classes are quite heavy (most are 100+ properties with around 3 attributes each). I stumbled upon the Expression API and tried throwing something together, but it proved to be fruitless. The performance hit is still very noticeable. As I said, I just stumbled upon the Expression API so I'm sure I'm doing something wrong.

The heavy stuff:

public async Task<IEnumerable<DTOPropertyInfo>> GetPropertiesInfoAsync(BaseDTO dto)
{
    List<DTOPropertyInfo> info = new();
    List<DTOPropertyInfo> favorites = new();
    QueryType type = dto.ToQueryType();
    PropertyInfo[] properties = dto.GetType().GetProperties();

    for (int i = 0; i < properties.Length; i++)
    {
        PropertyInfo property = properties[i];
        DisplayDataAttribute display = 
            (DisplayDataAttribute)property.GetCustomAttribute(typeof(DisplayDataAttribute));
        if (display is null)
        {
            continue;
        }

        object value = property.GetValue(dto);

        if (value is BaseDTO[] dtos)
        {
            for (int j = 0; j < dtos.Length; j++)
            {
                IEnumerable<DTOPropertyInfo> nestedInfo =
                    await GetPropertiesInfoAsync(dtos[j]);
                info.Add(new()
                {
                    DisplayName = $"{display.DisplayName} {j + 1}",
                    Value = nestedInfo,
                    Section = Section.SubSection
                });
            }
            continue;
        }
        else if (value is string[] strings)
        {
            if (strings.Length == 0)
            {
                continue;
            }

            List<DTOPropertyInfo> dtoProperties = new();
            for (int j = 0; j < strings.Length; j++)
            {
                dtoProperties.Add(new()
                {
                    DisplayName = (j + 1).ToString(),
                    Value = strings[j]
                });
            }

            info.Add(new()
            {
                DisplayName = display.DisplayName,
                Value = dtoProperties,
                Section = Section.SubSection
            });
            continue;
        }
        else if (property.PropertyType.IsArray)
        {
            //Only support arrays of type string[] and BaseDTO[]
            //If more needed, add them to the if-chain
            continue;
        }

        value = (value as string).FormatDisplayValue();
        if (string.IsNullOrEmpty(value.ToString()))
        {
            continue;
        }


        SectionAttribute section =
            (SectionAttribute)property.GetCustomAttribute(typeof(SectionAttribute));
        if (section is null)
        {
            section = (SectionAttribute)dto.GetType().GetCustomAttribute(typeof(SectionAttribute));
            if (section is null)
            {
                continue;
            }
        }

        if (type is not QueryType.None)
        {
            string favorite = await storage.GetAsync($"{type}/{display.DisplayName}");
            if (!string.IsNullOrEmpty(favorite))
            {
                favorites.Add(new()
                {
                    DisplayName = favorite,
                    Value = value,
                    IsFavorite = true,
                    Section = section.Section,
                    Unit = display.Unit
                });
                continue;
            }
        }

        info.Add(new()
        {
            DisplayName = display.DisplayName,
            Value = value,
            Section = section.Section,
            Unit = display.Unit
        });
    }

    info.InsertRange(0, favorites);
    return info;
}

The Expression API:

MethodInfo method = typeof(SettingsService).GetMethod(
            nameof(GetPropertiesInfoAsync),
            BindingFlags.Instance | BindingFlags.NonPublic,
            null,
            new[] { typeof(BaseDTO) },
            null);
        ConstantExpression constant = Expression.Constant(this, typeof(SettingsService));
        ParameterExpression parameter = Expression.Parameter(typeof(BaseDTO), "dto");
        MethodCallExpression call = Expression.Call(constant, method, parameter);
        LambdaExpression lambda = Expression.Lambda<Func<BaseDTO, Task<IEnumerable<DTOPropertyInfo>>>>(call, parameter);
        func = (Func<BaseDTO, Task<IEnumerable<DTOPropertyInfo>>>)lambda.Compile();

Then I simply the func variable when needed but there was no performance increase. What am I doing wrong?





Aucun commentaire:

Enregistrer un commentaire