Get attribute values from property and list values without knowing the attribute type
19,361
If you mean "given an attribute that takes one parameter, give me that value", for example:
[DisplayName("abc")] <===== "abc"
[Browsable(true)] <===== true
then this is easiest in .NET 4.5, via the new CustomAttributeData
API:
using System.ComponentModel;
using System.Reflection;
public static class Program
{
static void Main()
{
PropertyInfo prop = typeof(Foo).GetProperty("Bar");
var val = GetPropertyAttributes(prop, "DisplayName");
}
public static object GetPropertyAttributes(PropertyInfo prop, string attributeName)
{
// look for an attribute that takes one constructor argument
foreach(CustomAttributeData attribData in prop.GetCustomAttributesData())
{
string typeName = attribData.Constructor.DeclaringType.Name;
if(attribData.ConstructorArguments.Count == 1 &&
(typeName == attributeName || typeName == attributeName + "Attribute"))
{
return attribData.ConstructorArguments[0].Value;
}
}
return null;
}
}
class Foo
{
[DisplayName("abc")]
public string Bar { get; set; }
}
Author by
Steve Coleman
.NET developer C#, ASP/NET. MVC, WPF, WIN FORMS PL\SQL
Updated on August 01, 2022Comments
-
Steve Coleman over 1 year
I want to pass in the attribute name and return the value. This will be in a generic util and it will not know the attribute type.
Update This is the actual working code if someone needs to do this. I needed a way to have the core code parse the attributes without knowing what they were.
public void LoadPropertiesToGrid(BaseGridPropertyModel model) { foreach (PropertyInfo prop in ReflectionUtil.FindPublicPropeties(model)) { object editTyp = ReflectionUtil.GetPropertyAttributes(prop, "EditorType"); object rowIdx = ReflectionUtil.GetPropertyAttributes(prop, "ColIndex"); object name = ReflectionUtil.GetPropertyAttributes(prop, "Name"); object visible = ReflectionUtil.GetPropertyAttributes(prop, "Visible"); ConfigureColumn((string) name, (int) rowIdx, (bool) visible, (string) editTyp); } } [Serializable] public class CanvasPropertiesViewModel : BaseGridPropertyModel { [PropertiesGrid(Name = "TEsting Name 0", ColIndex = 0)] public string StringData1 { get; set; } [PropertiesGrid(Name = "TEsting Name 2", ColIndex = 2)] public string StringData2 { get; set; } [PropertiesGrid(Name = "TEsting Name 1", ColIndex = 1)] public string StringData3 { get; set; } } [AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)] public sealed class PropertiesGridAttribute : Attribute { /// <summary> /// Editor type /// </summary> public Type EditorType { get; set; } /// <summary> /// Sets Column Index /// </summary> public int ColIndex { get; set; } /// <summary> /// Visible to Grid /// </summary> public bool Visible { get; set; } /// <summary> /// Dispaly Name of the property /// </summary> public string Name { get; set; } } public static object GetPropertyAttributes(PropertyInfo prop, string attributeName) { // look for an attribute that takes one constructor argument foreach (CustomAttributeData attribData in prop.GetCustomAttributesData()) { string typeName = attribData.Constructor.DeclaringType.Name; //if (attribData.ConstructorArguments.Count == 1 && (typeName == attributeName || typeName == attributeName + "Attribute")) //{ // return attribData.ConstructorArguments[0].Value; //} foreach (CustomAttributeNamedArgument att in attribData.NamedArguments) { if(att.GetPropertyValue<string>("MemberName") == attributeName) { return att.TypedValue.Value; } } } return null; } //PropertyExpressionParser public static TRet GetPropertyValue<TRet>(this object obj, string propertyPathName) { if (obj == null) { throw new ArgumentNullException("obj"); } string[] parts = propertyPathName.Split('.'); string path = propertyPathName; object root = obj; if (parts.Length > 1) { path = parts[parts.Length - 1]; parts = parts.TakeWhile((p, i) => i < parts.Length - 1).ToArray(); string path2 = String.Join(".", parts); root = obj.GetPropertyValue<object>(path2); } var sourceType = root.GetType(); var value = (TRet)sourceType.GetProperty(path).GetValue(root, null); return value; }
-
Steve Coleman over 11 yearsThis would put me in the same position of knowing the interface type. Though I could create the interface in the core code to access the values...
-
Steve Konves over 11 yearsIn essence, knowing that a class (in this can a custom attribute) has a Value property is the same as declaring an interface with a Value property. If you don't have the ability to implement an interface with your custom attributes, you can still use reflection to find a property named Value.
-
Steve Coleman over 11 yearsThis works but it was not quite what I needed. I updated my questions with the answer based on your code. Thanks you got what I needed!
-
Steve Coleman over 11 yearsYep, That's what I did. Thanks for the help.