获取属性值和列表值而不知道属性类型

8
我想传入属性名称并返回其对应的值。这将在一个通用的工具中实现,该工具不知道属性的类型。 更新 以下是可行的代码,如果有人需要实现此功能可以参考。我需要一种方法使核心代码能够解析属性而不知道它们的具体内容。
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;
}

2
属性没有“Name”、“Value”的概念。你能给出一个示例,展示代码样本和期望的输出吗? - Marc Gravell
1
相关:https://dev59.com/X2w15IYBdhLWcg3wZq5r - Robert Harvey
2个回答

7
如果你的意思是“给定一个带有一个参数的属性,给我这个值”,例如:
[DisplayName("abc")] <===== "abc"
[Browsable(true)] <===== true

如果您使用的是.NET 4.5及以上版本,那么最简单的方法是通过新的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; }
}

这个可以用,但不完全符合我的需求。我根据你的代码更新了我的问题并得到了答案。谢谢,你提供了我需要的! - Steve Coleman

0

正如Mark所说,属性本身并没有值。但是你可以创建一个带有Value属性的接口,然后为每个自定义属性实现该接口。这样你只需要验证属性是否实现了该接口,然后获取其值。

示例:

public static object GetPropertyAttributes(PropertyInfo prop, string attributeName)
{
    object[] attrs = prop.GetCustomAttributes(true);

    foreach (object attr in attrs)
    {
        //THIS SHOULD BE REFLECTION
        if (attr is IMyCustomAttribute) // check if attr implements interface (you may have to reflect to get this)
        {
            return (attr as IMyCustomAttribute).Value
        }

    }
}

// Your interface
public interface IMyCustomAttribute
{
    object Value { get; set; }
}

// Attribute implementing interface
public SomeCustomAttribute : Attribute, IMyCustomAttribute
{
    object Value { get; set; }

    // Other attribute code goes here
}

这将使我处于了解接口类型的相同位置。虽然我可以在核心代码中创建接口来访问值... - Steve Coleman
本质上,知道一个类(在这种情况下是自定义属性)具有Value属性,就相当于声明了一个具有Value属性的接口。如果您没有能力使用自定义属性实现接口,仍然可以使用反射来查找名为Value的属性。 - Steve Konves
是的,这就是我所做的。感谢您的帮助。 - Steve Coleman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接