如何将获取属性特性的静态方法改造为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 infersTEntityasPersonfrom thep => p.Idexpression. 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)wherepis aPerson), which prevents subtle bugs. - Reusable Helper: The
GetMemberInfomethod 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
相关产品推荐
相关产品推荐

