3

I need the realType functionality of the following code as the Class in the Expression I am inspecting is a SubClass and memberExpression.Member returns information from the Base class.

This is for our blazor component library for the purposes of getting attributes on our Form models

Github Issue

I have read several articles and understand the problem and the solution however this raises a new issue in the context of net7 trimming.

Code taken from

https://stackoverflow.com/questions/9466582/how-to-get-the-child-declaring-type-from-an-expression

/// <summary>
/// Extracts the PropertyInfo for the property being accessed in the given expression.
/// </summary>
/// <remarks>
/// If possible, the actual owning type of the property is used, rather than the declaring class (so if "x" in "() => x.Foo" is a subclass overriding "Foo", then x's PropertyInfo for "Foo" is returned rather than the declaring base class's PropertyInfo for "Foo").
/// </remarks>
/// <typeparam name="T"></typeparam>
/// <param name="propertyExpression"></param>
/// <returns></returns>
internal static PropertyInfo ExtractPropertyInfo<T>(Expression<Func<T>> propertyExpression)
{
    if (propertyExpression == null)
    {
        throw new ArgumentNullException("propertyExpression");
    }

    var memberExpression = propertyExpression.Body as MemberExpression;
    if (memberExpression == null)
    {
        throw new ArgumentException(string.Format("Expression not a MemberExpresssion: {0}", propertyExpression), "propertyExpression");
    }

    var property = memberExpression.Member as PropertyInfo;
    if (property == null)
    {
        throw new ArgumentException(string.Format("Expression not a Property: {0}", propertyExpression), "propertyExpression");
    }

    var getMethod = property.GetGetMethod(true);
    if (getMethod.IsStatic)
    {
        throw new ArgumentException(string.Format("Expression cannot be static: {0}", propertyExpression), "propertyExpression");
    }

    Type realType = memberExpression.Expression.Type;
    if(realType == null) throw new ArgumentException(string.Format("Expression has no DeclaringType: {0}", propertyExpression), "propertyExpression");

    return realType.GetProperty(property.Name);
}

This code is perfect for my needs. The key to getting to the SubClass is this

Type realType = memberExpression.Expression.Type;

However the linker complains about this code in net7.

return realType.GetProperty(property.Name);

The compiler warning states that

(local variable) PropertyInfo property
'this' argument does not satisfy 'DynamicallyAccessedMemberTypes.PublicProperties' in call to 'System.Type.GetProperty(String)'. The return value of method 'System.Linq.Expressions.Expression.Type.get' does not have matching annotations. The source value must declare at least the same requirements as those declared on the target location it is assigned to. \[MudBlazor\]csharp(IL2075)

Since GetProperty is annotated with DynamicallyAccessedMemberTypes.PublicProperties but Type is not, the trimmer can't follow the full chain of annotations.

Can this code be made trim compatible? Will the trimmer know how to preserve the types (including child types) if I just ignore (pragma) this warning?

I tried to see how Type is implemented in netcore but it is a lookup on an internal Dictionary so I couldn't recreate the functionality. I also tried looking to see if I could ascertain the SubClass Type in some other "trim friendly" way.

  • Please see this github issue in the dotnet linker repo that provides some good insignts into trimming in the context of this question https://github.com/dotnet/linker/issues/3105 – Mike Surcouf Nov 12 '22 at 12:42

0 Answers0