You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将获取属性特性的静态方法改造为Type扩展方法,避免重复指定实体泛型类型

Solution: Type Extension Method Without Duplicate Generic Type Parameters

Got it, I understand you want to convert your static utility method into a Type extension that doesn't require repeating the entity type as a generic parameter. Here's how you can do it by leveraging generic type inference from the property selector expression, plus a quick validation step to ensure type consistency:

Complete Implementation

public static class TypeAttributeExtensions
{
    public static TAttr GetAttribute<TAttr, TEntity>(this Type type, Expression<Func<TEntity, object>> propertySelector) 
        where TAttr : Attribute
    {
        // Guard clause: Ensure the Type instance matches the entity type in the expression
        if (type != typeof(TEntity))
        {
            throw new ArgumentException(
                $"The provided Type ({type.Name}) does not match the entity type in the expression ({typeof(TEntity).Name}).", 
                nameof(type));
        }

        MemberExpression memberExpr = GetMemberInfo(propertySelector);
        string propertyName = memberExpr.Member.Name;

        return type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance)
            ?.GetCustomAttributes(typeof(TAttr), inherit: false)
            .Cast<TAttr>()
            .FirstOrDefault();
    }

    // Reusable helper to extract member info from the expression
    private static MemberExpression GetMemberInfo(Expression expression)
    {
        if (expression is not LambdaExpression lambda)
        {
            throw new ArgumentNullException(nameof(expression), "Expression must be a lambda.");
        }

        MemberExpression memberExpr = null;
        if (lambda.Body.NodeType == ExpressionType.Convert)
        {
            memberExpr = ((UnaryExpression)lambda.Body).Operand as MemberExpression;
        }
        else if (lambda.Body.NodeType == ExpressionType.MemberAccess)
        {
            memberExpr = lambda.Body as MemberExpression;
        }

        return memberExpr ?? throw new ArgumentException(
            "Expression must target a property or member access.", 
            nameof(expression));
    }
}

How It Works

  • Type Inference: When you write typeof(Person).GetAttribute<DisplayNameAttribute>(p => p.Id), the compiler automatically infers TEntity as Person from the p => p.Id expression. No need to specify it explicitly!
  • Validation: The guard clause ensures you can't accidentally pass a mismatched Type (e.g., typeof(Product).GetAttribute<DisplayNameAttribute>(p => p.Id) where p is a Person), which prevents subtle bugs.
  • Reusable Helper: The GetMemberInfo method is carried over from your original implementation, with improved error messages for clarity.

Example Usage

// Exactly the syntax you wanted!
var displayNameAttr = typeof(Person).GetAttribute<DisplayNameAttribute>(p => p.Id);

// If you need to check if the attribute exists:
if (displayNameAttr != null)
{
    Console.WriteLine($"Display name for Id: {displayNameAttr.DisplayName}");
}

This implementation keeps your code clean, maintains strong typing, and avoids the redundant generic parameter you wanted to eliminate.

内容的提问来源于stack exchange,提问作者XelaNimed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 12:12:41