type objeto new initialize anonimo c# .net anonymous-types

new - objeto anonimo c#



¿Cómo establecer el valor de la propiedad de un objeto anónimo? (7)

Este es mi código por ejemplo:

var output = new { NetSessionId = string.Empty }; foreach (var property in output.GetType().GetProperties()) { property.SetValue(output, "Test", null); }

Se produce una excepción: "No se encontró el método de conjunto de propiedades". Quiero saber cómo crear un tipo anónimo con propiedades que se pueden establecer.

Gracias.


¿Cómo establecer el valor de la propiedad de un objeto anónimo?

Como me recordaron hoy que nada es realmente inmutable cuando se utiliza la reflexión en combinación con el conocimiento sobre cómo se implementan ciertas cosas (campos de respaldo para las propiedades de solo lectura de tipos anónimos en este caso), pensé que sería una buena idea añadir una respuesta que ilustre cómo Los valores de propiedad de un objeto anónimo se pueden cambiar, asignándolos a sus campos de respaldo.

Este método se basa en una convención específica utilizada por el compilador para nombrar estos campos de respaldo: <xxxxx>i__Field en .NET y <xxxxx> en Mono, donde xxxxx representa el nombre de la propiedad. Si se cambiara esta convención, el código a continuación fallará (nota: también fallará si intenta darle algo que no sea de tipo anónimo).

public static class AnonymousObjectMutator { private const BindingFlags FieldFlags = BindingFlags.NonPublic | BindingFlags.Instance; private static readonly string[] BackingFieldFormats = { "<{0}>i__Field", "<{0}>" }; public static T Set<T, TProperty>( this T instance, Expression<Func<T, TProperty>> propExpression, TProperty newValue) where T : class { var pi = (propExpression.Body as MemberExpression).Member; var backingFieldNames = BackingFieldFormats.Select(x => string.Format(x, pi.Name)).ToList(); var fi = typeof(T) .GetFields(FieldFlags) .FirstOrDefault(f => backingFieldNames.Contains(f.Name)); if (fi == null) throw new NotSupportedException(string.Format("Cannot find backing field for {0}", pi.Name)); fi.SetValue(instance, newValue); return instance; } }

Muestra:

public static void Main(params string[] args) { var myAnonInstance = new { FirstField = "Hello", AnotherField = 30, }; Console.WriteLine(myAnonInstance); myAnonInstance .Set(x => x.FirstField, "Hello SO") .Set(x => x.AnotherField, 42); Console.WriteLine(myAnonInstance); }

Con salida:

{ FirstField = Hello, AnotherField = 30 } { FirstField = Hello SO, AnotherField = 42 }

Una versión un poco más elaborada se puede encontrar here


Las propiedades de tipo anónimo son de solo lectura y no se pueden establecer.

Los tipos anónimos proporcionan una manera conveniente de encapsular un conjunto de propiedades de solo lectura en un solo objeto sin tener que definir explícitamente un tipo primero. El nombre del tipo lo genera el compilador y no está disponible en el nivel del código fuente. El compilador deduce el tipo de cada propiedad.

Tipos anónimos (Guía de programación C #)


Los tipos anónimos son inmutables en C #. No creo que puedas cambiar la propiedad allí.


Si alguna vez te encuentras con una situación en la que necesitas un tipo mutable, en lugar de jugar con el tipo Anonymous , puedes usar ExpandoObject :

Ejemplo :

var people = new List<Person> { new Person { FirstName = "John", LastName = "Doe" }, new Person { FirstName = "Jane", LastName = "Doe" }, new Person { FirstName = "Bob", LastName = "Saget" }, new Person { FirstName = "William", LastName = "Drag" }, new Person { FirstName = "Richard", LastName = "Johnson" }, new Person { FirstName = "Robert", LastName = "Frost" } }; // Method syntax. var query = people.Select(p => { dynamic exp = new ExpandoObject(); exp.FirstName = p.FirstName; exp.LastName = p.LastName; return exp; }); // or people.Select(p => GetExpandoObject(p)) // Query syntax. var query2 = from p in people select GetExpandoObject(p); foreach (dynamic person in query2) // query2 or query { person.FirstName = "Changed"; Console.WriteLine("{0} {1}", person.FirstName, person.LastName); } // Used with the query syntax in this example, but may also be used // with the method syntax just as easily. private ExpandoObject GetExpandoObject(Person p) { dynamic exp = new ExpandoObject(); exp.FirstName = p.FirstName; exp.LastName = p.LastName; return exp; }


Tuve un escenario similar en el que tuve que asignar un código de error y un mensaje a numerosos tipos de objetos que comparten todas las propiedades anidadas específicas, por lo que no tengo que duplicar mis métodos de referencia con la esperanza de que ayude a otra persona:

public T AssignErrorMessage<T>(T response, string errorDescription, int errorCode) { PropertyInfo ErrorMessagesProperty = response.GetType().GetProperty("ErrorMessage"); if (ErrorMessagesProperty.GetValue(response, null) == null) ErrorMessagesProperty.SetValue(response, new ErrorMessage()); PropertyInfo ErrorCodeProperty = ErrorMessagesProperty.GetType().GetProperty("code"); ErrorCodeProperty.SetValue(response, errorCode); PropertyInfo ErrorMessageDescription = ErrorMessagesProperty.GetType().GetProperty("description"); ErrorMessageDescription.SetValue(response, errorDescription); return response; } public class ErrorMessage { public int code { get; set; } public string description { get; set; } }


Una forma fácil podría ser serializar el objeto anónimo en un Json con NewtonSoft''JsonConverter ( JsonConvert.SerializeObject(anonObject) ). Luego, puede cambiar el Json a través de la manipulación de cadenas y reserializarlo en un nuevo objeto anónimo que puede asignar a la variable anterior.

¡Un poco convoluto pero muy fácil de entender para principiantes!


Una sugerencia: puedes configurar todas las propiedades a la vez.

Las otras respuestas sugieren correctamente que son objetos inmutables (aunque la respuesta de Alex muestra cómo llegar a los campos de respaldo, lo que es una respuesta buena pero desordenada) pero tienen constructores expuestos, por lo que puede crear nuevas instancias.

Este ejemplo se clona a sí mismo por brevedad, pero puede ver cómo se podría usar el constructor para construir un objeto a partir de valores definidos.

var anonymousType = output.GetType(); var properties = anonymousType.GetProperties(); var propertyTypes = properties.Select(p => p.PropertyType).ToArray(); //The constructor has parameters for each property on the type var constructor = anonymousType.GetConstructor(propertyTypes); //clone the existing values to pass to ConstructorInfo var values = properties.Select(p => p.GetValue(output)).ToArray(); var anonymousClone = constructor.Invoke(values);