Могу ли я изменить значение существующего анонимного типа [duplicate]

Я обычно использую эту консольную команду для добавления новых банок в oracle:

exec dbms_java.loadjava('D:\temp\jcifs-1.3.19.jar');

В моем случае я добавил эту библиотеку для подключения к общим папкам Windows из установки oracle linux (smb). После установки вам может потребоваться предоставить пользователю разрешения.

20
задан Soner Gönül 3 July 2013 в 07:52
поделиться

7 ответов

Свойства анонимного типа доступны только для чтения, и они не могут быть установлены.

Анонимные типы предоставляют удобный способ инкапсулировать набор свойств только для чтения в один объект без явного определения тип первый. Имя типа генерируется компилятором и не доступно на уровне исходного кода. Тип каждого свойства выводится компилятором.

Анонимные типы (Руководство по программированию на C #)

26
ответ дан MarcinJuraszek 24 August 2018 в 19:32
поделиться

Как установить значение для свойства анонимного объекта?

Поскольку мне напомнили сегодня, что ничто не является действительно неизменным при использовании рефлексии в сочетании со знаниями о том, как определенные вещи (поддерживающие поля для свойств анонимного типа только для чтения), я счел целесообразным добавить ответ, иллюстрирующий изменение значений свойств анонимного объекта путем их сопоставления с их полями поддержки.

Этот метод основан на конкретном соглашении, используемом компилятором для именования этих полей поддержки: <xxxxx>i__Field в .NET и <xxxxx> в 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<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;
    }
}

Образец:

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 }

Здесь можно найти несколько более сложную версию здесь

16
ответ дан Alex 24 August 2018 в 19:32
поделиться

Простым способом может быть сериализация анонимного объекта в Json с помощью NewtonSoft'JsonConverter (JsonConvert.SerializeObject(anonObject)). Затем вы можете изменить Json с помощью строковых манипуляций и повторно инициализировать его в новый анонимный объект, который вы можете назначить старой переменной.

Немного свернуто, но очень легко понять для новичков!

0
ответ дан aveschini 24 August 2018 в 19:32
поделиться

Если вы когда-нибудь сталкивались с ситуацией, когда вам нужен изменяемый тип, вместо того, чтобы возиться с типом Anonymous, вы можете просто использовать ExpandoObject:

Пример:

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;
}
5
ответ дан B.K. 24 August 2018 в 19:32
поделиться

Предложение: вы можете сразу установить все свойства.

Другие ответы правильно указывают на то, что они являются неизменяемыми объектами (хотя ответ Алекса показывает, как добраться до полей поддержки, что является хорошим, но беспорядочный ответ), но у них есть открытые конструкторы, поэтому вы можете создавать новые экземпляры.

Этот пример клонирует себя для краткости, но вы можете видеть, как конструктор может использоваться для построения объекта из определенных значений.

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);
0
ответ дан Jono Stewart 24 August 2018 в 19:32
поделиться

У меня был аналогичный сценарий, когда мне нужно было назначить код ошибки и сообщение нескольким типам объектов, для которых все SHARE специфичные вложенные свойства, поэтому мне не нужно дублировать мои методы ссылки, надеясь, что это поможет кому-то еще:

    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; }
    }
0
ответ дан Rakan Murtada 24 August 2018 в 19:32
поделиться

Анонимные типы неизменяемы в C #. Я не думаю, что вы можете изменить свойство там.

1
ответ дан Shimmy 24 August 2018 в 19:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: