Estoy convirtiendo un objeto basado en una reflexión como esta.
obj.GetType().GetProperties()Produce la lista esperada de propiedades.
{Sistema.Reflexión.PropertyInfo[4]}
[0]: {Nombre de la cadena del sistema}
[1]: {Identificadores de System.Guid[]}
[2]: {Etiquetas System.String[]}
[3]: {System.Nullable`1[System.Boolean] Estado}
Luego, quiero borrar la lista de propiedades que no están en uso, así que agrego la condición de que el valor de una propiedad debe diferir de null .
obj.GetType().GetProperties() .Where(a => a.GetValue(obj) != null) Produce el resultado esperado para los campos atomarios pero no para las matrices (ya que indefiniblemente no son null , solo están vacíos).
{System.Linq.Enumerable.WhereArrayIterator<System.Reflection.PropertyInfo>}
[0]: {Nombre de la cadena del sistema}
[1]: {Identificadores de System.Guid[]}
[2]: {Etiquetas System.String[]}
No estoy seguro de cómo debo proceder para detectar propiedades de matriz no nulas pero vacías para excluirlas. No puedo simplemente convertir a una matriz (como se explica aquí ) porque no todas las propiedades son una matriz.
El acercamiento más cercano que tengo es esta pieza de "trabajo", que parece ser bastante... indeseable. Tiene este olor a código distinto.
obj.GetType().GetProperties() .Where(a => a.GetValue(obj) != null && !(a.GetValue(obj) is Array && (a.GetValue(obj) as Array).Length == 0)) Y cuando trato de crear algo con él usando Select(a=>a.GetValue(obj)) se vuelve aún más torpe y más obviamente necesita una mejora desesperada. También noté que cada vez que la matriz no está vacía, mi mapeo falla al producir System.String%5b%5d , lo que probablemente requerirá que clasifique adicionalmente el código.
No puedo pensar en una solución que sea significativamente diferente a la suya, fundamentalmente parece que es una lógica personalizada para determinar si el valor de una propiedad está "vacío" o no.
Sin embargo, tal vez una expresión de cambio que coincida con un patrón podría hacer que el código sea un poco más limpio, por ejemplo:
var obj = new MyObject { Name = "Test", Ids = new Guid[0], Tags = new[] { "t1" }, Status = null }; var values = obj.GetType().GetProperties() .Select(p => p.GetValue(obj)) .Where(o => o switch { Array array => array.Length > 0, _ => o != null });Puede simplificar la condición utilizando la coincidencia de patrones. Te permite llamar a GetValue solo una vez
p => p.GetValue(obj) is not null and not IList { Count: 0 }o con la versión un poco más corta
p => p.GetValue(obj) is not (null or IList { Count: 0 }) IList en lugar de matriz. Esto incluye matrices y también ArrayList y List<T> . Tenga en cuenta que una matriz expone su Length a través de la propiedad IList.Count implementada explícitamente también. "Implementado explícitamente" significa que este miembro está oculto o privado a menos que se vea directamente a través de la interfaz.
Incluso podría probar la interfaz ICollection en su lugar. Esto incluiría aún más colecciones.
IList { Count: 0 } es un patrón de propiedad que prueba si el objeto es un IList con un Count de 0.
Juntos:
var result = obj.GetType().GetProperties() .Where(p => p.GetValue(obj) is not (null or IList { Count: 0 }));Tenga en cuenta que esto usa patrones lógicos introducidos en C# 9.0.
Desafortunadamente, el olor del código cuando se trabaja con este reflejo ciego es en gran medida inevitable (hasta donde yo sé) y rara vez se condensa en un bloque apretado de forma limpia.
Su mapeo parece ser sensible al tipo de propiedad exacto dada la salida de string[] , aludiendo a que no puede desenvolver colecciones sin ayuda.
Para abordar ambos problemas, sugeriría un ayudante enumerable detallado donde los detalles de manejo de la colección sean inmediatamente evidentes para cualquier mantenedor futuro.
static IEnumerable<(Type Type, IEnumerable Values)> GetPopulatedPropertyData(object obj) { foreach (var prop in obj.GetType().GetProperties()) { var value = prop.GetValue(obj); if (value is Array a) { if (a.Length == 0) { continue; } yield return (prop.PropertyType.GetElementType()!, a); } // Future collections added in reverse hierarchial order here else if (value is not null) { yield return (prop.PropertyType, new[] { value }); } } }Esto debería facilitar el mapeo al hacer que el tipo correcto esté disponible mientras se mantiene la mayoría del código feo en su propia caja.