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