property from create all c# reflection properties getproperties

c# - from - Obtener propiedades en orden de declaración usando reflexión



get value property c# (7)

En .net 4.5 (e incluso .net 4.0 en vs2012) puede hacer mucho mejor con la reflexión utilizando el ingenioso truco con el atributo [CallerLineNumber] , permitiendo al compilador insertar el orden en sus propiedades por usted:

[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)] public sealed class OrderAttribute : Attribute { private readonly int order_; public OrderAttribute([CallerLineNumber]int order = 0) { order_ = order; } public int Order { get { return order_; } } } public class Test { //This sets order_ field to current line number [Order] public int Property2 { get; set; } //This sets order_ field to current line number [Order] public int Property1 { get; set; } }

Y luego usa la reflexión:

var properties = from property in typeof(Test).GetProperties() where Attribute.IsDefined(property, typeof(OrderAttribute)) orderby ((OrderAttribute)property .GetCustomAttributes(typeof(OrderAttribute), false) .Single()).Order select property; foreach (var property in properties) { // }

Si tiene que tratar con clases parciales, también puede ordenar las propiedades usando [CallerFilePath] .

Necesito obtener todas las propiedades usando el reflejo en el orden en que se declaran en la clase. Según MSDN, no se puede garantizar el orden cuando se usa GetProperties()

El método GetProperties no devuelve propiedades en un orden particular, como orden alfabético o de declaración.

Pero he leído que hay una solución al ordenar las propiedades por MetadataToken . Entonces mi pregunta es, ¿es seguro? No puedo encontrar información sobre MSDN al respecto. ¿O hay alguna otra forma de resolver este problema?

Mi implementación actual se ve de la siguiente manera:

var props = typeof(T) .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .OrderBy(x => x.MetadataToken);


Lo hice de esta manera:

internal static IEnumerable<Tuple<int,Type>> TypeHierarchy(this Type type) { var ct = type; var cl = 0; while (ct != null) { yield return new Tuple<int, Type>(cl,ct); ct = ct.BaseType; cl++; } } internal class PropertyInfoComparer : EqualityComparer<PropertyInfo> { public override bool Equals(PropertyInfo x, PropertyInfo y) { var equals= x.Name.Equals(y.Name); return equals; } public override int GetHashCode(PropertyInfo obj) { return obj.Name.GetHashCode(); } } internal static IEnumerable<PropertyInfo> GetRLPMembers(this Type type) { return type .TypeHierarchy() .SelectMany(t => t.Item2 .GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) .Where(prop => Attribute.IsDefined(prop, typeof(RLPAttribute))) .Select( pi=>new Tuple<int,PropertyInfo>(t.Item1,pi) ) ) .OrderByDescending(t => t.Item1) .ThenBy(t => t.Item2.GetCustomAttribute<RLPAttribute>().Order) .Select(p=>p.Item2) .Distinct(new PropertyInfoComparer()); }

con la propiedad declarada de la siguiente manera:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public class RLPAttribute : Attribute { private readonly int order_; public RLPAttribute([CallerLineNumber]int order = 0) { order_ = order; } public int Order { get { return order_; } } }


Lo que he probado clasificando por MetadataToken funciona.

Algunos de los usuarios afirman que esto de alguna manera no es un buen enfoque / no es confiable, pero aún no he visto ninguna evidencia de eso, ¿quizás puede publicar algún snipet de código aquí cuando el enfoque dado no funciona?

Acerca de la compatibilidad con versiones anteriores: mientras está trabajando en .net 4 / .net 4.5, Microsoft está haciendo .NET 5 o superior, por lo que puede suponer que este método de clasificación no se romperá en el futuro.

Por supuesto, para 2017, cuando se actualice a .net9, llegará a la ruptura de compatibilidad, pero para entonces los chicos de Microsoft probablemente descubrirán el "mecanismo de clasificación oficial". No tiene sentido retroceder o romper cosas.

Jugar con atributos adicionales para ordenar propiedades también lleva tiempo e implementación: ¿por qué molestarse si funciona la clasificación de MetadataToken?


Puede usar DisplayAttribute en System.Component.DataAnnotations, en lugar de atributo personalizado. Su requisito tiene que hacer algo con la pantalla de todos modos.


Según MSDN MetadataToken es único dentro de un Módulo, no hay nada que diga que garantice ningún orden.

INCLUSO si se comportó de la manera que usted quisiera, eso sería específico de la implementación y podría cambiar en cualquier momento sin previo aviso.

Vea esta antigua entrada de blog de MSDN .

Recomiendo encarecidamente mantenerse alejado de cualquier dependencia en tales detalles de implementación; vea esta respuesta de Marc Gravell .

Si necesita algo en tiempo de compilación, puede echar un vistazo a Roslyn (aunque está en una etapa muy temprana).


Si está satisfecho con la dependencia adicional, puede usar Protobuf-Net Marc Gravell para hacerlo sin tener que preocuparse por la mejor manera de implementar la reflexión y el almacenamiento en caché, etc. Simplemente decore sus campos con [ProtoMember] y luego acceda a los campos en numérico orden usando:

MetaType metaData = ProtoBuf.Meta.RuntimeTypeModel.Default[typeof(YourTypeName)]; metaData.GetFields();


Si vas por la ruta del atributo, aquí hay un método que he usado en el pasado;

public static IOrderedEnumerable<PropertyInfo> GetSortedProperties<T>() { return typeof(T) .GetProperties() .OrderBy(p => ((Order)p.GetCustomAttributes(typeof(Order), false)[0]).Order); }

Entonces úsalo así;

var test = new TestRecord { A = 1, B = 2, C = 3 }; foreach (var prop in GetSortedProperties<TestRecord>()) { Console.WriteLine(prop.GetValue(test, null)); }

Dónde;

class TestRecord { [Order(1)] public int A { get; set; } [Order(2)] public int B { get; set; } [Order(3)] public int C { get; set; } }

El método no funcionará si lo ejecuta en un tipo sin atributos comparables en todas sus propiedades obviamente, así que tenga cuidado de cómo se usa y debería ser suficiente para el requisito.

He omitido la definición de Order: Attribute ya que hay una buena muestra en el enlace de Yahia a la publicación de Marc Gravell.