Pregunta

El título lo dice todo.Cuando estoy reflexionando un poco sobre mis clases, ¿el método MemberInfo.GetCustomAttributes() preservará el orden de los atributos de un miembro o no?La documentación oficial no dice nada en un sentido ni en otro.


En caso de que te preguntes por qué necesitaría esto, aquí tienes la explicación completa.Es largo y no es necesario para la pregunta tal como se plantea ahora, pero tal vez alguien pueda encontrar una solución alternativa al problema mayor que no implique depender del orden de enumeración de atributos.

Estoy intentando crear un marco flexible para una aplicación (ASP.NET) que se espera que tenga una vida útil bastante larga.A lo largo del curso, obtendrá muchos formularios a los que deberá acceder desde el menú.Para hacer la vida más fácil a los futuros desarrolladores, he creado un MenuItemAttribute que puede aplicar a la clase de un formulario.Este atributo tiene una cantidad ilimitada de parámetros de cadena en su constructor, lo que permite al desarrollador especificar dónde residirá exactamente el formulario en el menú.Un ejemplo de uso típico sería algo como [MenuItem("Company", "Clients", "Orders")] lo que significaría que el menú debería tener un elemento "Empresa" debajo del cual habría un elemento "Clientes" debajo del cual habría un elemento "Pedidos", que luego abriría el formulario.Un solo formulario puede tener varios de estos atributos si es necesario; entonces será accesible desde varios lugares del menú.

Obviamente, todo el menú se crea en tiempo de ejecución enumerando todas las clases en mis ensamblajes y buscando este atributo.Sin embargo, recientemente recibí una solicitud para que los elementos del menú se ordenen de una manera predefinida.Los formularios que tienen funciones relacionadas deben estar uno al lado del otro en el menú.Tenga en cuenta que NO se trata de una clasificación alfabética, sino de un orden predefinido que especifican los desarrolladores.

Esto trae entonces el problema: ¿cómo especifico el orden en estos atributos?desde uno MenuItemAttribute describe una jerarquía completa, la especificación de pedido también debe incluir números de pedido para toda (o al menos una parte) de la jerarquía.No es suficiente un número de pedido sólo para el nivel inferior de la jerarquía.

Podría hacer otro atributo... MenuItemOrderHintAttribute, pero eso traería problemas con los casos en los que hay más de un MenuItemAttribute.De ahí la pregunta original.

También podría extender el MenuItemAttribute tomar dos matrices o una matriz de pares, pero eso complicaría mucho la sintaxis.La última idea es que podría hacer que las cadenas tengan un formato especial, pero eso sería bastante complicado en mi humilde opinión.


Vale, tengo otra idea.Usemos el orden que sugirió Jon Skeet.Esto permitirá especificar el orden para el último nivel de la jerarquía, no para los superiores.Pero podría modificar el atributo para que se aplique no sólo a las clases, sino también al conjunto mismo.En este caso el elemento del menú no tendría un formulario asociado.A nivel de ensamblaje, estos atributos podrían usarse para especificar el orden entre los niveles superiores de la jerarquía.

Se trata entonces de una compensación entre un sistema de menú centralizado y descentralizado.¿Alguna idea de por qué esto sería una mala idea?

¿Fue útil?

Solución

Pondría un solo valor extra (opcional) en el constructor MenuItemAttribute, que es " order " o " prioridad " ;:

[MenuItem(0, "Company", "Clients", "Orders")]
[MenuItem(1, "Foo", "Bar", "Baz")]

No estoy diciendo que sería bonito, pero efectivamente le permitiría especificar el pedido.

Otros consejos

El orden léxico de elementos en un archivo no está absolutamente garantizado de ninguna manera en los ensambles CIL resultantes ni de ser respetado en los resultados devueltos por Reflection. ¡Ni siquiera se garantiza que este pedido sea el mismo en llamadas repetidas dentro del mismo dominio de la aplicación!

Tenga en cuenta que MS ha roto este orden en otras partes de la reflexión en el pasado (observando como lo hicieron que esto realmente causó algunos problemas para algunos de sus códigos), por lo tanto, incluso si sucede que funciona en este momento, no hay nada detener esta ruptura en el futuro o en diferentes plataformas.

Considere cambiar su modelo de atributo para permitir expresar la información semántica directamente en lugar de confiar en el pedido.

Lamentablemente no, no puedes garantizar que el orden será el mismo que el orden en el que los especificaste.

Editar:una solución

Descargo de responsabilidad:Pido disculpas de antemano si no entiendo bien su problema final.

Suena como si necesitaras poder pasar n número de cuerdas para MenuItemAttribute y tiene MenuItemAttribute mantenga el orden de estas cadenas tal como lo ingresó el desarrollador en el constructor de atributos.

Aquí hay una posible solución:

Tener MenuItemAttribute usar una LinkedList<String> para mantener su estado.Entonces puedes iterar el params String[] en su constructor y agréguelos al LinkedList<String> que mantendría el orden.

Me parece que su problema realmente se debe al hecho de que los formularios están especificando dónde aparecen en su menú, lo que significa que está tratando de crear un menú combinando todos los formularios en un ensamblaje. Puede ser más fácil si especifica la estructura del menú por separado de cualquier formulario y resuelve los formularios de varias propiedades / atributos definidos en la clase correspondiente a un elemento del menú.

por ejemplo

public class MenuItem
{
    string Text { get; }
    Type FormType { get; }
    ICollection<MenuItem> SubItems { get; }
}

Luego, cuando se selecciona un elemento de menú, resuelva el formulario de alguna manera y muéstrelo. Este enfoque tiene la desventaja de que cualquier formulario nuevo necesita un cambio en el código que especifica la estructura del menú junto con el formulario en sí, pero eso será bastante menor ...

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top