通过prop名称获取通用代码中的value / obj ref

时间:2018-04-23 08:26:10

标签: c# generics properties

我最近创建了通用sql命令生成代码。一切都有效,除了我目前正在努力的一件事。 如何通过给定的属性名称获取Answer prop的实例/值?

我有什么:

将问题实例作为对象(例如myObject)

问题的属性+内部道具名称(字符串)+内部类型

[Table("Question")]
public class Question
{
    [Column("QuestionID", true)]
    public int QuestionId { get; set; }

    [Column("Number")]
    public string Nr { get; set; }

    [Column("CorrectAnswer", typeof(Answer), nameof(Answer.Text))]
    public Answer CorrectAnswer { get; set; }
}


[AttributeUsage(AttributeTargets.Property, Inherited = false)]
public class ColumnAttribute : DatabaseAttribute
{
    public bool IsTechnicalId { get; private set; } = false;
    public string DeepPropName { get; private set; } = null;
    public Type DeepClass { get; private set; } = null;
    public bool HasDeepProp { get; private set; } = false;

    public ColumnAttribute(string name) : base(name)
    {

    }

    /// <summary>
    /// Creates a deep object property column definition
    /// </summary>
    /// <param name="name"></param>
    /// <param name="deepProperty"></param>
    public ColumnAttribute(string name, Type deepClass, string deepPropertyName) : base(name)
    {
        DeepPropName = deepPropertyName;
        DeepClass = deepClass;
        HasDeepProp = true;
    }

    public ColumnAttribute(string name, bool isTechnicalId) : this(name)
    {
        IsTechnicalId = isTechnicalId;
    }
}

我获取道具和值的当前代码如下所示。

   public static IEnumerable<DatabaseAttributeContainer> GetAllAttributes<TClass>(TClass obj, bool inherit = false)
        {
            List<DatabaseAttributeContainer> propValues = new List<DatabaseAttributeContainer>();
            object value = null;
            Type classType = typeof(TClass);
            PropertyInfo[] pInfos = inherit ? classType.GetProperties() : classType.GetProperties(_NonInheritedFlag);
            DatabaseAttribute[] attributes = null;
            DatabaseAttribute attr = null;
            ColumnAttribute colAttr = null;
            PropertyInfo[] pInfosDeep = null;
            foreach (PropertyInfo pInfo in pInfos)
            {
                attributes = (DatabaseAttribute[])pInfo.GetCustomAttributes(typeof(DatabaseAttribute));
                attr = attributes.FirstOrDefault();
                if(!(attr is IgnoreAttribute))
                {
                    colAttr = (ColumnAttribute)attr;
                    //broken                       
                    if(colAttr.HasDeepProp)
                    {
                        pInfosDeep = colAttr.DeepClass.GetProperties(_NonInheritedFlag);
                        foreach (PropertyInfo pInfoDeep in pInfosDeep)
                        {
                            if(pInfoDeep.Name == colAttr.DeepPropName)
                            {
                                //Need object instance of Answer for "GetValue()"
                                //value = pInfoDeep.GetValue(obj, null);
                                break;
                            }
                        }
                    }
                    //broken end
                    else
                    {
                        if (obj != null)
                            value = pInfo.GetValue(obj, null);
                        propValues.Add(new DatabaseAttributeContainer(attr, value));
                    }
                }
            }
            propValues.Add(GetAttributeByClass<TClass>());
            if (propValues.Count == 0)
                throw new ApplicationException(typeof(TClass) + "has no DatabaseAttribute attribute");
            return propValues;
        }

除了唯一的例外,一切都完美无缺:如何在搜索对象中获取另一个对象的属性值? 我能够获取实例化对象的任何属性实例吗?

EDIT1:

我可以得到裁判
if(pInfo.Name == "CorrectAnswer") 
   answerRef = pInfo.GetValue(obj, null);

然后从answerRef castet获取道具来回答获得价值 对于我给定的propName

1 个答案:

答案 0 :(得分:0)

解决方案

public static IEnumerable<DatabaseAttributeContainer> GetAllAttributes<TClass>(TClass obj, bool inherit = false)
        {
            List<DatabaseAttributeContainer> propValues = new List<DatabaseAttributeContainer>();
            object value = null;
            Type classType = typeof(TClass);
            PropertyInfo[] pInfos = inherit ? classType.GetProperties() : classType.GetProperties(_NonInheritedFlag);
            DatabaseAttribute[] attributes = null;
            DatabaseAttribute attr = null;
            ColumnAttribute colAttr = null;
            PropertyInfo pInfoDeep = null;
            object deepRef = null;
            //ToDo: get custom attributes from this obj and iterate over it with prop name
            //get propInfo (performance increase)

            foreach (PropertyInfo pInfo in pInfos)
            {
                attributes = (DatabaseAttribute[])pInfo.GetCustomAttributes(typeof(DatabaseAttribute));
                attr = attributes.FirstOrDefault();
                if (!(attr is IgnoreAttribute))
                {
                    colAttr = attr as ColumnAttribute;
                    if (colAttr != null && colAttr.HasDeepProp && obj != null)
                    {
                        //get ref value
                        deepRef = pInfo.GetValue(obj, null);
                        deepRef = Convert.ChangeType(deepRef, colAttr.DeepType);
                        pInfoDeep = deepRef.GetType().GetProperty(colAttr.DeepPropName);
                        if (pInfoDeep == null)
                            throw new ApplicationException("Property with name " + colAttr.DeepPropName + " not found");
                        value = pInfoDeep.GetValue(deepRef, null);
                    }
                    else
                    {
                        if (obj != null)
                            value = pInfo.GetValue(obj, null);
                    }
                    propValues.Add(new DatabaseAttributeContainer(attr, value));
                }
            }
            propValues.Add(GetAttributeByClass<TClass>());
            if (propValues.Count == 0)
                throw new ApplicationException(typeof(TClass) + "has no DatabaseAttribute attribute");
            return propValues;
        }