Reflection blazor - 获取属性名称+值

yTo*_*ide 8 c# razor asp.net-core blazor

在我的父组件上我有这个:

<TestComponent @bind-Value="testString" />

@code {
    [MaxLength(10)]
    private string testString;
}
Run Code Online (Sandbox Code Playgroud)

关于我的TestComponent这个:

<input type="text" @bind="Value" @bind:event="oninput" />

@code {
    [Parameter] public string Value { get; set; }
    [Parameter] public EventCallback<string> ValueChanged { get; set; }

    protected override void OnInitialized() {
        //Get MaxLength here
    }
}
Run Code Online (Sandbox Code Playgroud)

我如何检查我的TestComponentifValue有 aMaxLength并获取他的值(如果有)?

Ven*_*sky 6

我已经需要检查用于DisplayName渲染标签的属性并向标签Required添加红色*,但我不知道如何执行此操作,我尝试了正常的方法,但没有成功。

但后来我想起 Blazor 已经这样做了ValidationMessage,因为它从属性获取属性并验证它......所以我决定检查它的源代码。

深入挖掘后,我发现这个函数解释了如何做我们需要的事情。

首先,它有一个Expression<Func<T>>参数,在 blazor 中是 的For属性ValidationMessage,所以我们可以在这里看到,可能不可能使用绑定值来做到这一点,或者只是像这样传递它Foo="@Foo"(如果可能的话,他们可能会这样做),所以我们需要另一个属性来传递该类型

例如

<TestComponent @bind-Value="testString" Field=@"(() => testString)" />
Run Code Online (Sandbox Code Playgroud)

现在继续该函数的代码,它将获取Body表达式的 并进行一些检查以获取并确保您正在传递属性。
然后就是这一行。

fieldName = memberExpression.Member.Name;
Run Code Online (Sandbox Code Playgroud)

如果您查看memberExpression.Member并致电,GetCustomAttributes您将获得我们所需要的内容,即该属性的所有自定义属性。

所以现在我们需要的只是循环自定义属性并做你想做的事情。

这是一个简化版本,用于获取CustomAttribute返回的属性Expression<Func<T>>

private IEnumerable<CustomAttributeData> GetExpressionCustomAttributes<T>(Expression<Func<T>> accessor)
{
    var accessorBody = accessor.Body;

    // Unwrap casts to object
    if (accessorBody is UnaryExpression unaryExpression
        && unaryExpression.NodeType == ExpressionType.Convert
        && unaryExpression.Type == typeof(object))
    {
        accessorBody = unaryExpression.Operand;
    }

    if (!(accessorBody is MemberExpression memberExpression))
    {
        throw new ArgumentException($"The provided expression contains a {accessorBody.GetType().Name} which is not supported. {nameof(FieldIdentifier)} only supports simple member accessors (fields, properties) of an object.");
    }

    return memberExpression.Member.GetCustomAttributes();
}
Run Code Online (Sandbox Code Playgroud)

以您为例,这是解决方法

。剃刀

<TestComponent @bind-Value="testString" Field="(() => testString)" />

@code {
    [MaxLength(10)]
    private string testString;
}
Run Code Online (Sandbox Code Playgroud)

测试组件.razor

<input type="text" @bind="Value" @bind:event="oninput" />

@code {
    [Parameter] public Expression<Func<string>>Field { get; set; }
    [Parameter] public string Value { get; set; }
    [Parameter] public EventCallback<string> ValueChanged { get; set; }

    protected override void OnInitialized()
    {
        base.OnInitialized();
        if (Field != null)
        {
            var attrs = GetExpressionCustomAttributes(Field);

            foreach (var attr in attrs)
            {   
                if(attr is MaxLengthAttribute maxLengthAttribute)
                {
                    // Do what you want with maxLengthAttribute     
                }
            }
        }
    }

    private IEnumerable<CustomAttributeData> GetExpressionCustomAttributes<T>(Expression<Func<T>> accessor)
    {
        var accessorBody = accessor.Body;
    
        // Unwrap casts to object
        if (accessorBody is UnaryExpression unaryExpression
            && unaryExpression.NodeType == ExpressionType.Convert
            && unaryExpression.Type == typeof(object))
        {
            accessorBody = unaryExpression.Operand;
        }
    
        if (!(accessorBody is MemberExpression memberExpression))
        {
            throw new ArgumentException($"The provided expression contains a {accessorBody.GetType().Name} which is not supported. {nameof(FieldIdentifier)} only supports simple member accessors (fields, properties) of an object.");
        }
    
        return memberExpression.Member.GetCustomAttributes();
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您只有一个属性,您还可以调用memberExpression.Member.GetCustomAttributes<Attribute>()以获取该属性类型的列表。

长话短说

向组件添加新属性

[Parameter] public Expression<Func<T>>Field { get; set; }
Run Code Online (Sandbox Code Playgroud)

使用此 gist辅助函数来获取您想要的属性。