Сначала перебираете свойства базового типа при вызове Reflection GetMembers? - PullRequest
2 голосов
/ 27 декабря 2010

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

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

Источник:

using System;

class Program 
{
        class SomeClass
        {
            public string First { get; set; }
            public int Second;
        }

        class AnotherClass : SomeClass
        {
            public int Third { get; set; }
            public string Fourth;
        } 

        public static void Main()
        {
            var obj = new AnotherClass { First = "asd", Second = 10};

            foreach (var member in obj.GetType().GetMembers())
            {
                Console.WriteLine(member.Name);
            }
        }
}

Вывод:

    get_Third
    set_Third
    get_First
    set_First
    Equals
    GetHashCode
    GetType
    ToString
    .ctor
    Third
    First
    Fourth
    Second

Вы можете проверить прогон здесь .

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

Еще один вопрос в той же строке: при поиске членов свойства идут первыми, а поля вторыми.В любом случае, чтобы изменить это поведение, или созданные метаданные всегда будут представлены в таком порядке?

Спасибо!

Ответы [ 3 ]

1 голос
/ 27 декабря 2010

Для доступа к базовому типу используйте BaseType свойство.

Чтобы проверить, объявлен ли член в том же типе, используйте свойство DeclaringType :

public static bool DeclaredInType(Type typeToCheck, MemberInfo member)
{
    return typeToCheck.Equals(member.DeclaringType);
}    

РЕДАКТИРОВАТЬ: вы можете сортировать по типу с помощью LINQ:

public static MemberInfo[] SortMembers(IEnumerable<MemberInfo> members)
{
    return members.OrderBy(m => m.GetType().Name)
                  .ToArray();
}
0 голосов
/ 01 марта 2017

TL; DR

    orderby typeof(T).Equals(mi.DeclaringType) ? 1 : -1

будет сначала толкать базовый memberInfo и сохранять порядок, определенный в классе.

Полный ответ:

для достижения той же целии используя DeclaringType, как предлагалось ранее, я определил следующий метод:

    public static IEnumerable<MemberInfo> GetAllFieldsAndPropertiesOfClass<T>()
    {
        return
            from mi in typeof(T).GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
            let ignoreAttr = (IgnoreSerializationAttribute)Attribute.GetCustomAttribute(mi, typeof(IgnoreSerializationAttribute))
            where (mi.MemberType == MemberTypes.Field || mi.MemberType == MemberTypes.Property)
               && (ignoreAttr == null || ignoreAttr != null && !ignoreAttr.Ignore)
            orderby typeof(T).Equals(mi.DeclaringType) ? 1 : -1
            select mi;
    }

В этом методе я также определил пользовательский атрибут, который явно игнорирует некоторые свойства из сериализации:

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class IgnoreSerializationAttribute : Attribute
{
    public bool Ignore { get; private set; }

    public IgnoreSerializationAttribute(bool ignore)
    {
        Ignore = ignore;
    }
}

Также можно добавить другой пользовательский атрибут для определения порядка, например

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class ColumnOrderAttribute : Attribute
{
    public int Order { get; private set; }

    public ColumnOrderAttribute(int order)
    {
        Order = order;
    }
}

, используемый следующим образом:

    public static IEnumerable<MemberInfo> GetAllFieldsAndPropertiesOfClassOrdered<T>()
    {
        return
            from mi in GetAllFieldsAndPropertiesOfClass<T>()
            let orderAttr = (ColumnOrderAttribute)Attribute.GetCustomAttribute(mi, typeof(ColumnOrderAttribute))
            orderby orderAttr == null ? int.MaxValue : orderAttr.Order, mi.Name
            select mi;
    }

Я использую эти методы для сериализации списка объектовиспользование других объектов в файлах CSV ...

0 голосов
/ 25 июля 2014

Это не совсем ответ на ОП (и я немного опаздываю), но я просто опишу, что я сделал, в надежде, что кто-то может найти это полезным.

У меня есть самодельная программа, которая сериализуется в XML. Он управляется списком объектов CopierField, которые я создаю и которые содержат данные, необходимые для ускорения сериализации. Вот сильно отредактированная версия этого класса:

  private class CopierField
  {
     // Name of the field or property and a reference to the declaring Type
     public string MemberName;
     public Type DeclaringType;

     // Reference to the FieldInfo or PropertyInfo object for this field or property. One of 
     //  these will be null and the other non-null.
     public FieldInfo MemberInfoForField = null;
     public PropertyInfo MemberInfoForProperty = null;

     // Ordering of this field, as returned by Type.GetMembers(). This is only used while 
     //  building the List<> of these objects for XML serialization
     public int FieldOrder;


     /// <summary>
     /// Comparison method that can be used to sort a collection of CopierField objects so they 
     /// are in the order wanted for XML serialization. This ordering is dependent on the depth 
     /// of derivation, and when that is equal it maintains the original ordering.
     /// </summary>
     public static readonly Comparison<CopierField> CompareForXml =
                        delegate(CopierField a, CopierField b)
                        {
                           int aDepth = GetTypeDepth(a.DeclaringType);
                           int bDepth = GetTypeDepth(b.DeclaringType);
                           if (aDepth != bDepth)
                              return aDepth.CompareTo(bDepth);

                           return a.FieldOrder.CompareTo(b.FieldOrder);
                        };


     /// <summary>
     /// Method to determine the depth of derivation for a type.
     /// </summary>
     private static int GetTypeDepth(Type aType)
     {
        int i = 0;
        while (aType.BaseType != null)
        {
           i++;
           aType = aType.BaseType;
        }
        return i;
     }
  }

Перед сериализацией типа объекта в XML в первый раз я создаю Список этих объектов, отсортированный в нужном мне порядке, используя метод, похожий на этот, где входные данные представляют собой Список объектов CopierField, который основан на данных из Тип .GetMembers ().

  private static List<CopierField> CreateCopierFieldListForXml(List<CopierField> copierFields)
  {
     // Build the new list, and note the original ordering as created by Type.GetMembers()
     List<CopierField> copierFieldsForXml = new List<CopierField>(copierFields.Count);
     for (int listIndex = 0; listIndex < copierFields.Count; listIndex++)
     {
        CopierField copierField = copierFields[listIndex];
        copierField.FieldOrder = listIndex;
        copierFieldsForXml.Add(copierField);
     }

     // Sort the new list as wanted for XML serialization
     copierFieldsForXml.Sort(CopierField.CompareForXml);
     return copierFieldsForXml;
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...