web-dev-qa-db-ja.com

C#で匿名型をキー/値配列に変換しますか?

次の匿名タイプがあります。

new {data1 = "test1", data2 = "sam", data3 = "bob"}

これを取り込み、キー値のペアを配列または辞書に出力するメソッドが必要です。

私の目標は、これをHttpRequestのポストデータとして使用して、最終的に次の文字列に連結することです。

"data1=test1&data2=sam&data3=bob"
73
Chris Kooken

これを達成するには、ほんの少しの反省が必要です。

var a = new { data1 = "test1", data2 = "sam", data3 = "bob" };
var type = a.GetType();
var props = type.GetProperties();
var pairs = props.Select(x => x.Name + "=" + x.GetValue(a, null)).ToArray();
var result = string.Join("&", pairs);
111
kbrimington

.NET 3.5 SP1または.NET 4を使用している場合、このために RouteValueDictionary を使用(ab)できます。 IDictionary<string, object>には、objectを受け入れ、プロパティをキーと値のペアに変換するコンストラクターがあります。

キーと値をループしてクエリ文字列を作成するのは簡単です。

61
GWB

RouteValueDictionaryでの方法は次のとおりです。

  private void AddValues(object values)
    {
        if (values != null)
        {
            foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values))
            {
                object obj2 = descriptor.GetValue(values);
                this.Add(descriptor.Name, obj2);
            }
        }
    }

完全なソースはこちら: http://Pastebin.com/c1gQpBMG

25
John

私はこのようなことをしました:

public class ObjectDictionary : Dictionary<string, object>
{
    /// <summary>
    /// Construct.
    /// </summary>
    /// <param name="a_source">Source object.</param>
    public ObjectDictionary(object a_source)
        : base(ParseObject(a_source))
    {

    }

    /// <summary>
    /// Create a dictionary from the given object (<paramref name="a_source"/>).
    /// </summary>
    /// <param name="a_source">Source object.</param>
    /// <returns>Created dictionary.</returns>
    /// <exception cref="ArgumentNullException">Thrown if <paramref name="a_source"/> is null.</exception>
    private static IDictionary<String, Object> ParseObject(object a_source)
    {
        #region Argument Validation

        if (a_source == null)
            throw new ArgumentNullException("a_source");

        #endregion

        var type = a_source.GetType();
        var props = type.GetProperties();

        return props.ToDictionary(x => x.Name, x => x.GetValue(a_source, null));
    }
}
1
Jordan

匿名オブジェクトを辞書に変換する組み込みの方法があります。

HtmlHelper.AnonymousObjectToHtmlAttributes(yourObj)

また、RouteValueDictionaryも返します。静的であることに注意してください

1
Xymanek

RouteValueDictionaryを使用するという@GWBの提案に基づいて、ネストされた匿名型をサポートするためにこの再帰関数を作成し、ネストされたパラメーターの前に親のキーを付けました。

public static string EncodeHtmlRequestBody(object data, string parent = null) {
    var keyValuePairs = new List<string>();
    var dict = new RouteValueDictionary(data);

    foreach (var pair in dict) {
        string key = parent == null ? pair.Key : parent + "." + pair.Key;
        var type = pair.Value.GetType();
        if (type.IsPrimitive || type == typeof(decimal) || type == typeof(string)) {
            keyValuePairs.Add(key + "=" + Uri.EscapeDataString((string)pair.Value).Replace("%20", "+"));
        } else {
            keyValuePairs.Add(EncodeHtmlRequestBody(pair.Value, key));
        }
    }

    return String.Join("&", keyValuePairs);
}

使用例:

var data = new {
    apiOperation = "AUTHORIZE",
    order = new {
        id = "order123",
        amount = "101.00",
        currency = "AUD"
    },
    transaction = new {
        id = "transaction123"
    },
    sourceOfFunds = new {
        type = "CARD",
        provided = new {
            card = new {
                expiry = new {
                    month = "1",
                    year = "20"
                },
                nameOnCard = "John Smith",
                number = "4444333322221111",
                securityCode = "123"
            }
        }
    }
};

string encodedData = EncodeHtmlRequestBody(data);

encodedDataは次のようになります。

"apiOperation=AUTHORIZE&order.id=order123&order.amount=101.00&order.currency=AUD&transaction.id=transaction123&sourceOfFunds.type=CARD&sourceOfFunds.provided.card.expiry.month=1&sourceOfFunds.provided.card.expiry.year=20&sourceOfFunds.provided.card.nameOnCard=John+Smith&sourceOfFunds.provided.card.number=4444333322221111&sourceOfFunds.provided.card.securityCode=123"

これが同様の状況で他の誰かを助けることを願っています。

編集: DrewGが指摘したように、これは配列をサポートしていません。匿名型の任意にネストされた配列のサポートを適切に実装することは簡単なことであり、使用したAPIのいずれも配列を受け入れていなかったため(フォームエンコーディングでそれらをシリアル化する標準化された方法もありません)、あなたがそれらをサポートする必要がある場合、私はあなたの人々にそれを任せます。

1
Extragorey

@kbrimingtonのソリューションはニース拡張メソッドを作成します-私の場合はHtmlStringを返します

    public static System.Web.HtmlString ToHTMLAttributeString(this Object attributes)
    {
        var props = attributes.GetType().GetProperties();
        var pairs = props.Select(x => string.Format(@"{0}=""{1}""",x.Name,x.GetValue(attributes, null))).ToArray();
        return new HtmlString(string.Join(" ", pairs));
    }

任意の属性をRazor MVCビューにドロップするために使用しています。 RouteValueDictionaryを使用して結果をループするコードから始めましたが、これは非常にすてきです。

1
Andiih
using Newtonsoft.Json;
var data = new {data1 = "test1", data2 = "sam", data3 = "bob"};
var encodedData = new FormUrlEncodedContent(JsonConvert.DeserializeObject<Dictionary<string, string>>(JsonConvert.SerializeObject(data))