获取对象和所有后代对象的所有字符串属性

时间:2018-08-11 18:09:01

标签: c# reflection

给出任何复杂的对象,例如:

public class Person
{
    public string Name { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public string Street { get; set; }
    public string City { get; set; }
}

我想使用 reflection 来获取string实例的所有Person和任何子对象(在这种情况下为Address),并且从理论上讲Address等中的潜在对象。在此示例中,这将为PropertyInfoPerson.NameAddress.Street

检索Address.City

3 个答案:

答案 0 :(得分:3)

您可以扫描属性 graph (将其设为 Breadth First Search -BFS)以获得所有公共属性:

private static IEnumerable<PropertyInfo> PublicProps(Type value) {
  HashSet<PropertyInfo> emitted = new HashSet<PropertyInfo>();

  BindingFlags flags = BindingFlags.Instance | BindingFlags.Public;

  List<PropertyInfo> agenda = value
    .GetProperties(flags)
    .ToList();

  while (agenda.Any()) {
    for (int i = agenda.Count - 1; i >= 0; --i) {
      PropertyInfo item = agenda[i];

      agenda.RemoveAt(i);

      if (!emitted.Add(item))
        continue;

      yield return item;

      agenda.AddRange(item.PropertyType.GetProperties(flags));
    }
  }
}

然后使用 Linq 过滤掉string属性:

var result = PublicProps(typeof(Person))
  .Where(prop => prop.CanRead) // to be on the safe side if you want to read
  .Where(prop => prop.PropertyType == typeof(string));

Console.WriteLine(string.Join(Environment.NewLine, result);

结果:

System.String Name
System.String City
System.String Street

请注意,递归不是一般情况下的解决方案,例如

public class Person {
  public string Name { get; set; }
  public Address Address { get; set; }
}

public class Address {
  public string Street { get; set; }
  public string City { get; set; }
  public Person HouseOwner { get; set; } // <- circular property
}

答案 1 :(得分:0)

using System;
using System.Reflection;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            getPRopNames(typeof(Person));

        }

        public static void getPRopNames(Type fromObject)
        {
            foreach (PropertyInfo oneProp in fromObject.GetProperties())
            {
                if (oneProp.PropertyType.IsValueType || oneProp.PropertyType == typeof(string))
                {
                    Console.WriteLine(oneProp.Name);
                }
                else
                {
                    getPRopNames(oneProp.PropertyType);
                }
            }
        }
    }

    public class Person
    {
        public string Name { get; set; }
        public Address Address { get; set; }
    }

    public class Address
    {
        public string Street { get; set; }
        public string City { get; set; }
    }
}

答案 2 :(得分:0)

您可以使用反射来扫描属性。

    public static void FindStringMembers(Type t, List<string>PropertyNames, int stackDepth = 0) 
    {
        if (stackDepth >= 10) {
            return;
        }

        var f = t.GetProperties();

        var stringProperties = f.Where(x => x.PropertyType == typeof(string)).Select(x => x.Name);

        PropertyNames.AddRange(stringProperties);

        var otherProperties = f.Where(x => x.PropertyType != typeof(string));

        foreach (var property in otherProperties) {
            FindStringMembers(property.PropertyType, PropertyNames, stackDepth + 1);
        }
    }

    static void Main(string[] args)
    {
        var bob = new Person();

        var deepScan = new List<string>();

        FindStringMembers(bob.GetType(), deepScan);

        Console.WriteLine(string.Join("\n", deepScan));

    }