Глубоко найти тип свойства в экземпляре класса - PullRequest
0 голосов
/ 16 января 2012

У меня есть метод, который анализирует xml и создает объект указанного типа из этого xml. Все это делается с использованием обобщений, чтобы иметь общий метод для всех типов.

Моя проблема в том, что я хочу искать свойство в различных классах, используя его имя типа (не по имени). Допустим, свойство имеет тип «type1», тогда некоторые определения класса объявлены ниже:

class foo1
{
  type1 prop1{get;set;}
}

class foo2
{
  foo1 prop2{get;set;}
}

class foo3:foo2
{
  type2 prop3{get;set;}
}

Для всех вышеупомянутых объявленных классов, если я создаю объекты, я хочу получить доступ к type1 типизированным свойствам для каждого экземпляра вышеупомянутых классов, т.е. я должен иметь возможность получить значение свойства, объявленного как type1, из объектов foo1, foo2, foo3 классы. Я действительно хочу общий способ сделать это, поскольку классы могут увеличиться.

1 Ответ

1 голос
/ 16 января 2012

Вот один из способов почти сделать это. Чего не хватает, так это того, что при использовании отражения BindingFlags.FlattenHierarchy не возвращает закрытые методы родительских классов. Маркировка этих типов как защищенных или открытых разрешит эту проблему. (Вы также можете вручную пройти через базовые классы, чтобы прочитать приватные члены.)

Если вы хотите найти в сборке все типы, которые объявляют свойство заданного типа, вы можете написать такой метод:

// using System.Reflection

public IEnumerable<Type> GetTypesWithPropertyOfType(Assembly a, Type t)
{
    BindingFlags propertyBindingFlags = BindingFlags.Public 
                                       | BindingFlags.NonPublic 
                                       | BindingFlags.Instance 
                                       | BindingFlags.FlattenHierarchy;

    // a property is kept if it is assignable from the type
    // parameter passed in            
    MemberFilter mf = (pi, crit)=>
          (pi as PropertyInfo)
          .PropertyType
          .IsAssignableFrom(t);

    // a class is kept if it contains at least one property that
    // passes the property filter.  All public and nonpublic properties of
    // the class, and public and protected properties of the base class,
    // are considered
    Func<Type, bool> ClassFilter = 
        c=>c.FindMembers(MemberTypes.Property, propertyBindingFlags, mf, null)
            .FirstOrDefault() != null;

    // return all classes in the assembly that match ClassFilter
    return
        a.GetTypes()
        .Where(c=>c.IsClass)
        .Where(ClassFilter);
}

Чтобы найти классы в исполняющей сборке, которые определяют или наследуют свойство типа type1, вы можете вызвать:

    var v = GetTypesWithPropertyOfType(
           Assembly.GetExecutingAssembly(),
           typeof(type1));

    foreach (var n in v) Console.WriteLine(n.FullName);

Это распечатывает foo1. Если ваш код, определяющий классы foo, изменен на (a) сделать foo1.prop1 общедоступным или защищенным и (b) сделать foo2 наследованным от foo1, то приведенный выше код выдает:

foo1
foo2
foo3

как и ожидалось.

...