@@ -19,7 +19,7 @@ namespace Azure.Monitor.OpenTelemetry.LiveMetrics.Internals.Filtering
1919 /// The filter's configuration (condition) is specified in a <see cref="FilterInfo"/> DTO.
2020 /// </summary>
2121 /// <typeparam name="TTelemetry">Type of telemetry documents.</typeparam>
22- internal class Filter < TTelemetry >
22+ internal class Filter < TTelemetry > where TTelemetry : DocumentIngress
2323 {
2424 private const string FieldNameCustomDimensionsPrefix = "CustomDimensions." ;
2525
@@ -56,15 +56,15 @@ internal class Filter<TTelemetry>
5656 new [ ] { typeof ( string ) , typeof ( NumberStyles ) , typeof ( IFormatProvider ) , typeof ( double ) . MakeByRefType ( ) } ) ;
5757
5858 private static readonly MethodInfo ListStringTryGetValueMethodInfo =
59- GetMethodInfo < IList < KeyValuePairString > , string , string > ( ( list , key ) => Filter < int > . TryGetString ( list , key ) ) ;
59+ GetMethodInfo < IList < KeyValuePairString > , string , string > ( ( list , key ) => TryGetString ( list , key ) ) ;
6060
6161 private static readonly MethodInfo DictionaryStringDoubleTryGetValueMethodInfo = typeof ( IDictionary < string , double > ) . GetMethod ( "TryGetValue" ) ;
6262
6363 private static readonly MethodInfo ListKeyValuePairStringScanMethodInfo =
64- GetMethodInfo < IList < KeyValuePairString > , string , bool > ( ( list , searchValue ) => Filter < int > . ScanList ( list , searchValue ) ) ;
64+ GetMethodInfo < IList < KeyValuePairString > , string , bool > ( ( list , searchValue ) => ScanList ( list , searchValue ) ) ;
6565
6666 private static readonly MethodInfo DictionaryStringDoubleScanMethodInfo =
67- GetMethodInfo < IDictionary < string , double > , string , bool > ( ( dict , searchValue ) => Filter < int > . ScanDictionary ( dict , searchValue ) ) ;
67+ GetMethodInfo < IDictionary < string , double > , string , bool > ( ( dict , searchValue ) => ScanDictionary ( dict , searchValue ) ) ;
6868
6969 private static readonly ConstantExpression DoubleDefaultNumberStyles = Expression . Constant ( NumberStyles . AllowLeadingWhite | NumberStyles . AllowTrailingWhite | NumberStyles . AllowLeadingSign | NumberStyles . AllowDecimalPoint | NumberStyles . AllowThousands | NumberStyles . AllowExponent ) ;
7070 private static readonly ConstantExpression InvariantCulture = Expression . Constant ( CultureInfo . InvariantCulture ) ;
@@ -218,12 +218,35 @@ public override string ToString()
218218 return info ? . ToString ( ) ?? string . Empty ;
219219 }
220220
221- internal static Expression ProduceFieldExpression ( ParameterExpression documentExpression , string fieldName , FieldNameType fieldNameType )
221+ [ UnconditionalSuppressMessage ( "AOT" , "IL2075" , Justification = "The DocumentIngress class and its derived classes have DynamicallyAccessedMembers attribute applied to preserve public properties." ) ]
222+ internal static Expression ProduceFieldExpression (
223+ ParameterExpression documentExpression ,
224+ string fieldName ,
225+ FieldNameType fieldNameType )
222226 {
223227 switch ( fieldNameType )
224228 {
225229 case FieldNameType . FieldName :
226- return fieldName . Split ( FieldNameTrainSeparator ) . Aggregate < string , Expression > ( documentExpression , Expression . Property ) ;
230+ Expression current = documentExpression ;
231+ string [ ] propertyNames = fieldName . Split ( FieldNameTrainSeparator ) ;
232+
233+ foreach ( string propertyName in propertyNames )
234+ {
235+ Type currentType = current . Type ;
236+ PropertyInfo propertyInfo = currentType . GetProperty ( propertyName , BindingFlags . Instance | BindingFlags . Public ) ;
237+
238+ if ( propertyInfo == null )
239+ {
240+ throw new ArgumentOutOfRangeException (
241+ nameof ( fieldName ) ,
242+ $ "Property '{ propertyName } ' not found on type '{ currentType . FullName } '") ;
243+ }
244+
245+ current = Expression . Property ( current , propertyInfo ) ;
246+ }
247+
248+ return current ;
249+
227250 case FieldNameType . CustomMetricName :
228251 string customMetricName = fieldName . Substring (
229252 FieldNameCustomMetricsPrefix . Length ,
@@ -276,21 +299,47 @@ internal static Type GetFieldType(string fieldName, out FieldNameType fieldNameT
276299 return GetPropertyTypeFromFieldName ( fieldName ) ;
277300 }
278301
279- private static Expression CreateListAccessExpression ( ParameterExpression documentExpression , string listName , MethodInfo tryGetValueMethodInfo , Type valueType , string keyValue )
302+ [ UnconditionalSuppressMessage ( "AOT" , "IL2075" , Justification = "The DocumentIngress class and its derived classes have DynamicallyAccessedMembers attribute applied to preserve public properties." ) ]
303+ private static Expression CreateListAccessExpression (
304+ ParameterExpression documentExpression ,
305+ string listName ,
306+ MethodInfo tryGetValueMethodInfo ,
307+ Type valueType ,
308+ string keyValue )
280309 {
310+ // Get the PropertyInfo directly to avoid string-based property access
311+ PropertyInfo listProperty = documentExpression . Type . GetProperty ( listName , BindingFlags . Instance | BindingFlags . Public ) ;
312+ if ( listProperty == null )
313+ {
314+ throw new ArgumentException ( $ "Property '{ listName } ' not found on type '{ documentExpression . Type . FullName } '", nameof ( listName ) ) ;
315+ }
316+
281317 // return Filter<int>.TryGetString(document.listName, keyValue)
282- MemberExpression properties = Expression . Property ( documentExpression , listName ) ;
318+ MemberExpression properties = Expression . Property ( documentExpression , listProperty ) ;
283319 return Expression . Call ( tryGetValueMethodInfo , properties , Expression . Constant ( keyValue ) ) ;
284320 }
285321
286- private static Expression CreateDictionaryAccessExpression ( ParameterExpression documentExpression , string dictionaryName , MethodInfo tryGetValueMethodInfo , Type valueType , string keyValue )
322+ [ UnconditionalSuppressMessage ( "AOT" , "IL2075" , Justification = "The DocumentIngress class and its derived classes have DynamicallyAccessedMembers attribute applied to preserve public properties." ) ]
323+ private static Expression CreateDictionaryAccessExpression (
324+ ParameterExpression documentExpression ,
325+ string dictionaryName ,
326+ MethodInfo tryGetValueMethodInfo ,
327+ Type valueType ,
328+ string keyValue )
287329 {
330+ // Get the PropertyInfo directly to avoid string-based property access
331+ PropertyInfo dictionaryProperty = documentExpression . Type . GetProperty ( dictionaryName , BindingFlags . Instance | BindingFlags . Public ) ;
332+ if ( dictionaryProperty == null )
333+ {
334+ throw new ArgumentException ( $ "Property '{ dictionaryName } ' not found on type '{ documentExpression . Type . FullName } '", nameof ( dictionaryName ) ) ;
335+ }
336+
288337 // valueType value;
289338 // document.dictionaryName.TryGetValue(keyValue, out value)
290339 // return value;
291340 ParameterExpression valueVariable = Expression . Variable ( valueType ) ;
292341
293- MemberExpression properties = Expression . Property ( documentExpression , dictionaryName ) ;
342+ MemberExpression properties = Expression . Property ( documentExpression , dictionaryProperty ) ;
294343 MethodCallExpression tryGetValueCall = Expression . Call ( properties , tryGetValueMethodInfo , Expression . Constant ( keyValue ) , valueVariable ) ;
295344
296345 // a block will "return" its last expression
0 commit comments