Как установить значение для свойства анонимного объекта?
blockquote>Поскольку мне напомнили сегодня, что ничто не является действительно неизменным при использовании рефлексии в сочетании со знаниями о том, как определенные вещи (поддерживающие поля для свойств анонимного типа только для чтения), я счел целесообразным добавить ответ, иллюстрирующий изменение значений свойств анонимного объекта путем их сопоставления с их полями поддержки.
Этот метод основан на конкретном соглашении, используемом компилятором для именования этих полей поддержки:
в .NET и
i__Field в Mono, с
xxxxx
, представляющим имя свойства. Если это соглашение должно было измениться, приведенный ниже код не сработает (обратите внимание: он также потерпит неудачу, если вы попытаетесь передать ему то, что не является анонимным типом).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
( this T instance, Expression > 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; } } Образец:
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); }
С выходом:
{ FirstField = Hello, AnotherField = 30 } { FirstField = Hello SO, AnotherField = 42 }
Здесь можно найти несколько более сложную версию здесь