4

クラスが Summary オブジェクトの List<> を保持する設計があり、各 Summary は半動的プロパティのディクショナリです。つまり、特定のリスト内のすべてのサマリーは、ディクショナリ内で同じキーを持ちます。この設計を使用して、動的な「プロパティ」のセットを構築し、プロジェクトの仕様に従って、これらの要約値を実行時に構成できるため、要約値を追跡します。

問題は、リスト内の各項目が辞書内のキーが実際のプロパティであるかのように扱われるように、このリストをフラット化するにはどうすればよいかということです。

Dictionary をリストに変換するさまざまなバリエーションを試しましたが、キーをプロパティとして扱う必要があるため、本質的に間違っているようです。C# 4.0+ の新しい動的機能と ExpandoObject を使用する必要があると思いますが、うまくいきません。

以下のコードは基本的なセットアップを示しています。「flattenedSummary」を使用すると、必要なものが得られます。つまり、プロパティがサマリーのディクショナリのキーである動的な型の新しいリストです。ただし、プロパティ名をハードコーディングしたという点で欠陥があり、実行時まで実際にはわからないため、それを行うことはできません。

flattenedSummary2 バージョンはリストを平坦化しようとしますが、返される型がまだリストであり、必要なリストではないため不十分です。

    public class Summary : Dictionary<string, object>
    {
    }

    public class ClassA
    {
        public List<Summary> Summaries = new List<Summary>();
    }

    static void Main(string[] args)
    {
        ClassA a = new ClassA();
        var summary = new Summary();
        summary.Add("Year", 2010);
        summary.Add("Income", 1000m);
        summary.Add("Expenses", 500m);
        a.Summaries.Add(summary);

        summary = new Summary();
        summary.Add("Year", 2011);
        summary.Add("Income", 2000m);
        summary.Add("Expenses", 700m);
        a.Summaries.Add(summary);

        summary = new Summary();
        summary.Add("Year", 2012);
        summary.Add("Income", 1000m);
        summary.Add("Expenses", 800m);
        a.Summaries.Add(summary);

        var flattenedSummary = from s in a.Summaries select new { Year = s["Year"], Income = s["Income"], Expenses = s["Expenses"] };
        ObjectDumper.Write(flattenedSummary, 1);

        var flattenedSummary2 = Convert(a);
        ObjectDumper.Write(flattenedSummary2, 1);

        Console.ReadKey();
    }

    public static List<ExpandoObject> Convert(ClassA a)
    {
        var list = new List<ExpandoObject>();
        foreach (Summary summary in a.Summaries)
        {
            IDictionary<string, object> fields = new ExpandoObject();
            foreach (var field in summary)
            {
                fields.Add(field.Key.ToString(), field.Value);
            }
            dynamic s = fields;
            list.Add(s);
        }

        return list;
    }
4

2 に答える 2

1

非常に近いので、私は Ed の答えを受け入れましたが、他の誰かが役に立つと思った場合に備えて、次のコードを提供しています。主な変更点は、最終的な List が動的になるように、ExpandoObject のすべての使用が動的として設定されるようにすることでした。これらの変更がなくても、リスト内の型を調べると、まだ ExpandoObject が返されました (たとえば、json シリアル化では、予期されるプロパティ名/値の代わりに ExpandoObject が返されました)。

まず、ToExpando() メソッド (おそらく ToDynamic と呼ばれるはずです):

public static dynamic ToExpando(this IDictionary<string, object> dictionary)
{
    dynamic expando = new ExpandoObject();
    var expandoDic = (IDictionary<string, object>)expando;

    // go through the items in the dictionary and copy over the key value pairs)
    foreach (var kvp in dictionary)
    {
        // if the value can also be turned into an ExpandoObject, then do it!
        if (kvp.Value is IDictionary<string, object>)
        {
            var expandoValue = ((IDictionary<string, object>)kvp.Value).ToExpando();
            expandoDic.Add(kvp.Key, expandoValue);
        }
        else if (kvp.Value is ICollection)
        {
            // iterate through the collection and convert any strin-object dictionaries
            // along the way into expando objects
            var itemList = new List<object>();
            foreach (var item in (ICollection)kvp.Value)
            {
                if (item is IDictionary<string, object>)
                {
                    var expandoItem = ((IDictionary<string, object>)item).ToExpando();
                    itemList.Add(expandoItem);
                }
                else
                {
                    itemList.Add(item);
                }
            }

            expandoDic.Add(kvp.Key, itemList);
        }
        else
        {
            expandoDic.Add(kvp);
        }
    }

    return expando;
}

呼び出しコードは次のようになります。

    List<dynamic> summaries = new List<dynamic>();
    foreach (var s in a.Summaries)
    {
        summaries.Add(s.DynamicFields.ToExpando());
    }

または、さらにコンパクトなバージョン:

    a.Summaries.Select(s => s.DynamicFields.ToExpando())

上記のすべては、次のように参照できるオブジェクトを提供します。

    int year = a.Summaries[0].Year; // Year is a dynamic property of type int
    decimal income = a.Summaries[0].Income; // Income is a dynamic property of type decimal

もちろん、プロパティはわかりませんが、json にシリアル化するか、微調整して、表示目的でグリッドやその他の UI 要素をバインドするために使用できます。

于 2014-09-25T06:39:12.513 に答える
1

ダニエル、

この記事には、あなたに役立つ可能性のある解決策が記載されています。 http://theburningmonk.com/2011/05/idictionarystring-object-to-expandoobject-extension-method/

したがって、拡張メソッドを作成します...

  public static ExpandoObject ToExpando(this IDictionary<string, object> dictionary)
        {
            var expando = new ExpandoObject();
            var expandoDic = (IDictionary<string, object>)expando;

            // go through the items in the dictionary and copy over the key value pairs)
            foreach (var kvp in dictionary)
            {
                // if the value can also be turned into an ExpandoObject, then do it!
                if (kvp.Value is IDictionary<string, object>)
                {
                    var expandoValue = ((IDictionary<string, object>)kvp.Value).ToExpando();
                    expandoDic.Add(kvp.Key, expandoValue);
                }
                else if (kvp.Value is ICollection)
                {
                    // iterate through the collection and convert any strin-object dictionaries
                    // along the way into expando objects
                    var itemList = new List<object>();
                    foreach (var item in (ICollection)kvp.Value)
                    {
                        if (item is IDictionary<string, object>)
                        {
                            var expandoItem = ((IDictionary<string, object>)item).ToExpando();
                            itemList.Add(expandoItem);
                        }
                        else
                        {
                            itemList.Add(item);
                        }
                    }

                    expandoDic.Add(kvp.Key, itemList);
                }
                else
                {
                    expandoDic.Add(kvp);
                }
            }

            return expando;
        }

次に、メイン関数から...

List<ExpandoObject> flattenSummary3 = new List<ExpandoObject>();
foreach ( var s in a.Summaries)
{
    flattenSummary3.Add(s.ToExpando());
}

そして、 flattenSummary3 変数には、プロパティで参照できる ExpandObjects のリストが含まれます。

これが役立つことを願っています。

于 2014-09-25T03:11:52.750 に答える