I have this:
public class Demo
{
[Description("Hello World!")]
public int SomeProp { get; set; }
}
I want the description. So I wrote this:
public string? GetDescription<TType, TProperty>(Expression<Func<TType, TProperty>> expression)
where TType : class
{
var memberName = ((MemberExpression)expression.Body).Member.Name;
var description = typeof(TType).GetMember(memberName).First()
.GetCustomAttribute<DescriptionAttribute>()
?.Description;
return description;
}
Which can be used like this:
var description = GetDescription<Demo, string>(x => x.SomeProp);
But what I want is this:
var description = GetDescription<Demo>(x => x.SomeProp); // no TProperty
I hoped type inference would infer TProperty
and simplify the callsite, but I can't compile without it ("Using the generic method requires 2 type arguments").
How can I do this?
One way is to just take a Func<TType, object>
. When the property type is not object
, the root expression node will be a Convert
expression, so you just need to check for that.
public static string? GetDescription<TType>(Expression<Func<TType, object?>> expression)
where TType : class
{
var body = expression.Body;
string memberName;
if (body is MemberExpression exp1) {
memberName = exp1.Member.Name;
} else if (body is UnaryExpression unary &&
unary.NodeType == ExpressionType.Convert &&
unary.Operand is MemberExpression exp2) {
memberName = exp2.Member.Name;
} else {
throw new NotSupportedException();
}
var description = typeof(TType).GetMember(memberName).First()
.GetCustomAttribute<DescriptionAttribute>()
?.Description;
return description;
}
Or, you can change the use-site and explicitly write the parameter type of the lambda, instead of explicitly writing the type arguments of GetDescription
.
GetDescription((Demo x) => x.SomeProp)
Side note:
You already got the MemberInfo
from the expression, so why not just get the attribute straight from there?
public static string? GetDescription<TType>(Expression<Func<TType, object>> expression)
where TType : class
{
var body = expression.Body;
MemberInfo member;
if (body is MemberExpression exp1) {
member = exp1.Member;
} else if (body is UnaryExpression unary &&
unary.NodeType == ExpressionType.Convert &&
unary.Operand is MemberExpression exp2) {
member = exp2.Member;
} else {
throw new NotSupportedException();
}
var description = member
.GetCustomAttribute<DescriptionAttribute>()
?.Description;
return description;
}