Как определить, было ли переопределено свойство?

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

Цель состоит в том, чтобы найти все свойства, которые находятся на вершине дерева.

так что в основном

public class A{
    public int Property1 { get; set; }
}

public class B : A{
    public int Property2 { get; set; }
    public virtual int Property3 { get; set; }
}

public class C : B{
    public override int Property3 { get; set; }
    public int Property4 { get; set; }
    public int Property5 { get; set; }
}

Конечный результат будет примерно таким

A.Property1  
B.Property2  
B.Property3  
C.Property4  
C.Property5  

Если вы заметили, что я не хочу принимать переопределенные свойства из-за того, как я ищу свойства, если я делаю что-то вроде этого

Например, C.Property3, и он не может его найти, он проверит базовый тип C и найдет его.

Это то, что у меня есть до сих пор.

public static void RegisterType( Type type )
{
    PropertyInfo[] properties = type.GetProperties( BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.GetProperty | BindingFlags.SetProperty );

    if ( properties != null && properties.Length > 0 )
    {
        foreach ( PropertyInfo property in properties )
        {
            // if the property is an indexers then we ignore them
            if ( property.Name == "Item" && property.GetIndexParameters().Length > 0 )
                continue;

            // We don't want Arrays or Generic Property Types
            if ( (property.PropertyType.IsArray || property.PropertyType.IsGenericType) )
                continue;

            // Register Property
        }
    }
}

Я хочу следующее:

  • Общедоступные свойства, которые не переопределены, не статичны, не закрыты
  • Допускаются либо свойства get, либо set
  • Они не являются массивом или универсальным типом.
  • Они являются вершиной дерева, т.е. класс C в примере является самым высоким (пример списка свойств - это именно то, что я ищу)
  • Они не являются свойством индексатора ( this[index] )

person Benjamin    schedule 22.12.2010    source источник


Ответы (2)


Чтобы игнорировать унаследованные члены, вы можете использовать флаг BindingFlags.DeclaredOnly, который вы уже делаете.

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

Type type = typeof(Foo);

foreach ( var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) {
    var getMethod = property.GetGetMethod(false);
    if (getMethod.GetBaseDefinition() == getMethod) {
        Console.WriteLine(getMethod);
    }
}

Если свойство переопределено, его 'getter' MethodInfo вернет информацию MethodInfo, отличную от GetBaseDefinition.

person Josh    schedule 22.12.2010
comment
поэтому getMethod.Dump(); если они совпадают, то зарегистрируйтесь? если не игнорируют? - person Benjamin; 22.12.2010
comment
Извините, это артефакт, оставшийся от моего тестирования в LinqPad. Я изменил его на Console.WriteLine. - person Josh; 22.12.2010
comment
если getMethod.GetBaseDefinition() == getMethod, то вы знаете, что это исходное свойство, а не переопределенное свойство. - person Josh; 22.12.2010

Ни одно из этих решений не сработало в моем случае. В итоге я использовал DeclaringType для определения различий в определениях (я предоставил полную функцию, чтобы дать некоторый контекст):

static public String GetExpandedInfo(Exception e)
{
    StringBuilder info = new StringBuilder();
    Type exceptionType = e.GetType();

    // only get properties declared in this type (i.e. not inherited from System.Exception)
    PropertyInfo[] propertyInfo = exceptionType.GetProperties(System.Reflection.BindingFlags.DeclaredOnly | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
    if (propertyInfo.Length > 0)
    {
        // add the exception class name at the top
        info.AppendFormat("[{0}]\n", exceptionType.Name);

        foreach (PropertyInfo prop in propertyInfo)
        {
            // check the property isn't overriding a System.Exception property (i.e. Message)
            // as that is a default property accessible via the generic Exception class handlers
            var getMethod = prop.GetGetMethod(false);
            if (getMethod.GetBaseDefinition().DeclaringType == getMethod.DeclaringType)
            {
                // add the property name and it's value
                info.AppendFormat("{0}: {1}\n", prop.Name, prop.GetValue(e, null));
            }
        }
    }
person Stuart Gillibrand    schedule 02.07.2014