I have the following class structure:
MyAttribute.cs
public sealed class MyAttribute : Attribute
{
public MyAttribute(string name)
{
if (string.IsNullOrEmpty(name))
{
throw new ArgumentNullException(nameof(name));
}
Name = name;
}
public string Name { get; }
}
Matrix.cs
public class Matrix
{
[MyAttribute("awesome_name")]
public string AwesomeName { get; set; }
}
And we make an method to "extract" the value defined on name
of MyAttribute
:
AttributeExtensions.cs
public static class AttributeExtensions
{
public static string GetMyAttributeNameOfProperty<TClass>(Expression<Func<TClass, object>> expression)
{
if (expression.Body is MemberExpression memberExpression)
{
var propertyInfo = (PropertyInfo)memberExpression.Member;
var hasMyAttribute = propertyInfo.IsDefined(typeof(MyAttribute), false);
if (hasMyAttribute)
{
return propertyInfo.GetCustomAttribute<MyAttribute>().Name;
}
}
return default;
}
}
Finally, we call this way:
AttributeExtensions.GetMyAttributeNameOfProperty<Matrix>(exp => exp.AwesomeName)
This call, returns: "awesome_name"
We have some doubts:
Exists an more "clean" way to pass the property of
<TClass>(exp.AwesomeName)
to this extension method?We really need of
Expression<>
? It's possible to make this only withFunc<TClass, object>
?
Like:
GetMyAttributeNameOfProperty<TClass>(Func<TClass, object> expression)
Any suggestions?
1 Answer 1
I'd suggest:
public static class AttributeExtensions
{
public static string GetMyAttributeNameOfProperty<TClass>(string propertyName)
{
var propertyInfo = typeof(TClass).GetProperty(propertyName);
return propertyInfo?.GetCustomAttribute<MyAttribute>()?.Name ?? default;
}
}
Usage:
var awesome = AttributeExtensions.GetMyAttributeNameOfProperty<Matrix>(nameof(Matrix.AwesomeName));
Console.WriteLine(awesome);
Note: The above isn't an extension method. The below code is.
public static class AttributeExtensions
{
public static string GetMyAttributeNameOfProperty<TType>(this TType me, string propertyName) where TType : Type
{
var propertyInfo = me.GetProperty(propertyName);
return propertyInfo?.GetCustomAttribute<MyAttribute>()?.Name ?? default;
}
}
Usage:
var awesome = typeof(Matrix).GetMyAttributeNameOfProperty(nameof(Matrix.AwesomeName));
Console.WriteLine(awesome);
Both output:
awesome_name
Benefits:
- Does not use an
Expression
or even the namespaceSystem.Linq.Expressions
- Won't throw an exception (returns
null
if property or attribute doesn't exist) - Using
nameof
makes refactoring safe in the event you rename class properties - Does not use
Func<TClass, object>
or similar - Does not require an instance of
Matrix
(or any other type since it's generic)
Either way works and is really a matter of preference. There are pros and cons to using extension methods.
-
\$\begingroup\$ Thanks @Zer0! We make this on the past, we try to simplify our call so we don't have to use
typeof(Matrix)
andnameof(Matrix.AwesomeName)
this make it more verbose... +1 \$\endgroup\$Igor– Igor2020年03月18日 19:08:43 +00:00Commented Mar 18, 2020 at 19:08 -
2\$\begingroup\$ @Igor Using
Func<TClass, Object>
withoutExpression
is not going to help since you'll get the value ofAwesomeName
and we only care about the type. I could write a method with the signatureFunc<TClass, Type>
and calling it withexp => exp.AwesomeName.GetType()
if you want. But I don't find that any less verbose than the above suggestions. If you really want to avoidtypeof
,nameof
andGetType()
I'd stick with the method signature you already have. \$\endgroup\$Zer0– Zer02020年03月18日 19:33:00 +00:00Commented Mar 18, 2020 at 19:33 -
\$\begingroup\$ This is the way... Cheers! \$\endgroup\$Igor– Igor2020年03月19日 15:40:54 +00:00Commented Mar 19, 2020 at 15:40
-
1\$\begingroup\$ @Igor Glad to hear it. Please mark as answer if you think this solved your question. I can edit in the
Func<TClass, Type>
solution if you'd like. \$\endgroup\$Zer0– Zer02020年03月21日 23:05:07 +00:00Commented Mar 21, 2020 at 23:05 -
\$\begingroup\$ Hey @Zer0, when I comment: "This is the way" I meant this part: " I'd stick with the method signature you already have." \$\endgroup\$Igor– Igor2020年03月22日 03:39:03 +00:00Commented Mar 22, 2020 at 3:39
AttributeExtensions.GetMyAttributeNameOfProperty<Matrix>(exp => exp.AwesomeName)"
Please, don't vote down! This is an solution and fully works! \$\endgroup\$