web-dev-qa-db-ja.com

匿名オブジェクトのプロパティに値を設定する方法は?

これは例えば私のコードです:

var output = new
{
    NetSessionId = string.Empty
};

foreach (var property in output.GetType().GetProperties())
{
    property.SetValue(output, "Test", null);
}

「プロパティセットメソッドが見つかりません」という例外が発生します。設定可能なプロパティを使用して匿名型を作成する方法を知りたいです。

ありがとう。

24
Leo Vo

匿名型のプロパティは読み取り専用であり、設定できません。

匿名型は、最初に型を明示的に定義することなく読み取り専用プロパティのセットを単一のオブジェクトにカプセル化する便利な方法を提供します。型名はコンパイラーによって生成され、ソースコードレベルでは使用できません。各プロパティのタイプは、コンパイラによって推測されます。

匿名型(C#プログラミングガイド)

32
MarcinJuraszek

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.

匿名型はC#では不変です。そこでプロパティを変更できるとは思わない。

1
Stay Foolish

提案:すべてのプロパティを一度に設定できます。

他の答えは、それらが不変のオブジェクトであることを正しく示唆しています(アレックスの答えは、バッキングフィールドに到達する方法を示していますが、これは良いが、厄介な答えです)が、コンストラクタが公開されているため、新しいインスタンスを作成できます。

この例では簡潔にするために自分自身のクローンを作成していますが、コンストラクターを使用して定義済みの値からオブジェクトを作成する方法を確認できます。

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

簡単な方法は、NewtonSoft'JsonConverter(JsonConvert.SerializeObject(anonObject))を使用してJsonの匿名オブジェクトをシリアル化することです。次に、文字列操作でJsonを変更し、古い変数に割り当てることができる新しい匿名オブジェクトに再シリアル化できます。

少し畳み込みますが、初心者には本当に簡単に理解できます!

0
aveschini

エラーコードとメッセージを、すべての共有固有のネストされたプロパティを持つ多数のオブジェクトタイプに割り当てる必要がある同様のシナリオがありました。

    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