. Net отражение, чтобы получить вложенное свойство с пользовательским атрибутом - PullRequest
0 голосов
/ 22 апреля 2020

Я хочу знать, как лучше всего получить информацию и значение проп с помощью отражения для вложенного класса по имени его пользовательского атрибута. С помощью приведенного ниже кода я могу получить реквизиты через рекурсию. Но есть ли лучший способ или с помощью LINQ. Обратите внимание, что я не хочу жестко кодировать тип класса как аналогичный другому решению

Я также хочу получить значение свойства с помощью пользовательского атрибута

например, var propValue = ?????

 public class PlanetRoot

    {

        public void GetNeighborMoon()

        {

            Planet planet = new Planet();

            Product product = new Product();

            Neighbor neighbor = new Neighbor();

            neighbor.Moons = 10;

            neighbor.RingColor = "Red";

            product.Neighbors = new List<Neighbor>();

            product.Neighbors.Add(neighbor);

            planet.Product = product;



            //1. Get the RingColor property info of neighbor with attribute MyDBField(Name = "NeighborRing") . Is there a better way

            PropertyInfo propInfo = null;
            DoRecursiveGetProperty(planet.GetType(), "NeighborRing", out propInfo );



            //2. Get the RingColor property value of neighbor with attribute MyDBField(Name = "NeighborRing")

            //var propValue = GetPropertyValue(????);

        }

    }



    private static PropertyInfo DoRecursiveGetProperty(Type type, string attribName, out PropertyInfo propInfo)

    {

        PropertyInfo[] pi = type.GetProperties();

        propInfo= null;

        foreach (PropertyInfo p in pi)

        {

            var dbFieldAttribute = (MyDBFieldAttribute)Attribute.GetCustomAttribute(p, typeof(MyDBFieldAttribute));

            if (dbFieldAttribute != null && attribName.ToUpper() == dbFieldAttribute.Name.ToUpper())

            {

                propInfo= p;

                //Console.WriteLine(p.Name + " : " + (dbFieldAttribute != null && dbFieldAttribute.Name != null ? dbFieldAttribute.Name : "****"));

                return true;

            }



            if (p.PropertyType.IsClass && !p.PropertyType.IsValueType && !p.PropertyType.IsPrimitive

            && p.PropertyType.FullName != "System.String")
                if (propInfo != null) return true;
                else DoRecursiveGetProperty(p.PropertyType, attribName, out propInfo);



        }



        return false;



    }

    public class Planet

    {

        public string PlanetId { get; set; }

        public string Name { get; set; }

        public string Description { get; set; }

        public Product Product { get; set; }



        [MyDBField(Name="PubDate")]

        public string Publishdate { get; set; }



    }



    public class Product

    {

        public string ProductId { get; set; }

        public List<Neighbor> Neighbors { get; set; }



    }



    public class Neighbor

    {

        [MyDBField(Name = "NeighborRing")]

        public string RingColor { get; set; }

        public int Moons { get; set; }

    }



    public class MyDBFieldAttribute : System.Attribute

    {

        public string Name { get; set; }

    }

1 Ответ

0 голосов
/ 22 апреля 2020

Чтобы получить значение для вложенного члена, который может быть в коллекции, необходимо выполнить итерацию коллекций и отслеживать текущий объект.

Предполагая, что вам не нужен полученный PropInfo по другим причинам просто попробуйте получить значение:

private static bool TryRecursiveGetValueWithMyDBFieldName(object startObject, string attribName, out object propValue) {
    PropertyInfo[] pi = startObject.GetType().GetProperties();

    foreach (PropertyInfo p in pi) {
        var dbFieldAttribute = (MyDBFieldAttribute)Attribute.GetCustomAttribute(p, typeof(MyDBFieldAttribute));
        if (dbFieldAttribute != null && dbFieldAttribute.Name.Equals(attribName, StringComparison.CurrentCultureIgnoreCase)) {
            //Console.WriteLine(p.Name + " : " + (dbFieldAttribute != null && dbFieldAttribute.Name != null ? dbFieldAttribute.Name : "****"));
            propValue = p.GetValue(startObject);
            return true;
        }

        if (p.PropertyType.IsClass && !p.PropertyType.IsValueType && !p.PropertyType.IsPrimitive &&
            !p.PropertyType.FullName.StartsWith("System.")) {
            var tryObject = p.GetValue(startObject);
            if (tryObject != null && TryRecursiveGetValueWithMyDBFieldName(tryObject, attribName, out propValue))
                return true;
        }

        if (p.PropertyType.IsClass && p.GetValue(startObject) is IEnumerable ip) {
            foreach (var obj in ip) {
                if (obj != null && TryRecursiveGetValueWithMyDBFieldName(obj, attribName, out propValue))
                    return true;
            }
        }
    }

    propValue = default;
    return false;
}

Чтобы использовать его, вызовите с начальным объектом:

var foundAttrib = TryRecursiveGetValueWithMyDBFieldName(planet, "NeighborRing", out var propValue);

ПРИМЕЧАНИЕ. Это вернет значение первого объекта с соответствующим атрибутом, как, например, каждый член List<Neighbor> будет иметь атрибут MyDBField со свойством Name NeighborRing.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...