C# - 动态添加对象(添加动态属性名称)

时间:2015-09-16 08:13:54

标签: c# json dynamic structure expandoobject

我试图创建一些动态ExpandoObject。我遇到了一个问题。

由于我不知道对象中这些不同属性的名称应该是什么,我不能这样做:

var list = new ArrayList();

var obj = new ExpandoObject();
obj.ID = 1,
obj.Product = "Pie",
obj.Days = 1,
obj.QTY = 65

list.Add(obj);

让我解释一下我的情况:我希望从随机数据库中获取数据(我不知道哪个,但是根据我从UI获得的信息建立连接字符串),因此我不知道知道我需要得到什么数据。这可能是数据库表的一个例子

表格销售

  • ID:int,
  • 产品:nvarchar(100),
  • 天:int,
  • 数量:bigint

这可能是另一个例子:

表Foobar

  • Id:int,
  • 天:int
  • 数量:bigint
  • Product_Id:int
  • Department_Id:int

如您所见,我不知道数据库的外观(这是100%匿名,因此需要100%动态),我想要返回的数据应该看起来像一个构造良好的JSON ,像这样:

[
  {
    "ID": 1,
    "Product": "Pie"
    "Days": 1,
    "QTY": 65
  },
  {
    "ID": 2,
    "Product": "Melons"
    "Days": 5,
    "QTY": 12
  }
]

或者,与另一个例子:

[
  {
    "ID": 1,
    "Days": 2,
    "QTY": 56,
    "Product_Id": 5,
    "Department_Id": 2
  }
  {
    "ID": 2,
    "Days": 6,
    "QTY": 12,
    "Product_Id": 2,
    "Department_Id": 5
  }
]

我已尝试使用这些ExpandoObject,但似乎无法使其正常工作,因为我无法做到这一点所示的内容问题(我不知道属性的名称)。有没有办法让我这么说:

var obj = new ExpandoObject();
var propName = "Product";

var obj.propName = "Pie"

Console.WriteLine("Let's print!: " + obj.Product);

//OUTPUT
Let's print!: Pie

有没有人有解决方案,只需指导一个结构,这可能会解决这种情况?

5 个答案:

答案 0 :(得分:4)

您可以创建ExpandoObject,而不是创建List<Dictionary<string, object>>或其他动态类型,其中每个Dictionary<string, object>包含您要序列化的名称/值对。然后使用Json.NET(或JavaScriptSerializer序列化为JSON,但不太灵活):

        var list = new List<Dictionary<string, object>>();

        // Build a dictionary entry using a dictionary initializer: https://msdn.microsoft.com/en-us/library/bb531208.aspx
        list.Add(new Dictionary<string, object> { { "ID", 1 }, {"Product", "Pie"}, {"Days", 1}, {"QTY", 65} });

        // Build a dictionary entry incrementally
        // See https://msdn.microsoft.com/en-us/library/xfhwa508%28v=vs.110%29.aspx
        var dict = new Dictionary<string, object>();
        dict["ID"] = 2;
        dict["Product"] = "Melons";
        dict["Days"] = 5;
        dict["QTY"] = 12;
        list.Add(dict);

        Console.WriteLine(JsonConvert.SerializeObject(list, Formatting.Indented));
        Console.WriteLine(new JavaScriptSerializer().Serialize(list));

第一个输出:

[
  {
    "ID": 1,
    "Product": "Pie",
    "Days": 1,
    "QTY": 65
  },
  {
    "ID": 2,
    "Product": "Melons",
    "Days": 5,
    "QTY": 12
  }
]

第二个输出相同而没有缩进:

[{"ID":1,"Product":"Pie","Days":1,"QTY":65},{"ID":2,"Product":"Melons","Days":5,"QTY":12}]

答案 1 :(得分:1)

使用dynamic,然后转换为IDictionary<string, object>以循环浏览您的媒体资源:

dynamic obj = new ExpandoObject();
obj.Product = "Pie";
obj.Quantity = 2;

// Loop through all added properties       
foreach(var prop in (IDictionary<string, object>)obj)
{
  Console.WriteLine(prop.Key + " : " + prop.Value);
}

我做了一个小提琴:https://dotnetfiddle.net/yFLy2u

现在这是你问题的解决方案......像@ dbc这样的其他答案可能更适合这个问题(这不是问题,真的)

答案 2 :(得分:0)

正如您在此处ExpandoObject Class所见,ExpandoObject正在实施IDictionary<string, object>,因此您可以使用

这样的事实
IDictionary<string, object> obj = new ExpandoObject();
var propName = "Product";
obj[propName] = "Pie"
Console.WriteLine("Let's print!: " + obj[propName]);
// Verify it's working
Console.WriteLine("Let's print again!: " + ((dynamic)obj).Product);

答案 3 :(得分:0)

在我写答案时,我看到你已经得到了正确答案。您可以使用Dictionary<string, onject>甚至Tuple

但是根据您的原始问题,您想要动态添加属性。为此,您可以使用ExpandoObject参考其他答案。这与使用ExpandoObject动态添加属性的解决方案相同,类似于您的代码。

//example classes
public class DictKey
{
    public string DisplayName { get; set; }
    public DictKey(string name) { DisplayName = name; }
}

public class DictValue
{
    public int ColumnIndex { get; set; }
    public DictValue(int idx) { ColumnIndex = idx; }
}

//utility method
public static IDictionary<string, object> GetExpando(KeyValuePair<DictKey, List<DictValue>> dictPair)
{
    IDictionary<string, object> dynamicObject = new ExpandoObject();
    dynamicObject["Station"] = dictPair.Key.DisplayName;
    foreach (var item in dictPair.Value)
    {
        dynamicObject["Month" + (item.ColumnIndex + 1)] = item;
    }
    return dynamicObject;
}

Ans用法示例:

var dictionaryByMonth = new Dictionary<DictKey, List<DictValue>>();
dictionaryByMonth.Add(new DictKey("Set1"), new List<DictValue> { new DictValue(0), new DictValue(2), new DictValue(4), new DictValue(6), new DictValue(8) });
dictionaryByMonth.Add(new DictKey("Set2"), new List<DictValue> { new DictValue(1), new DictValue(2), new DictValue(5), new DictValue(6), new DictValue(11) });

var rowsByMonth = dictionaryByMonth.Select(item => GetExpando(item));

答案 4 :(得分:-1)

第一部分,彻底阅读C#团队的this blog post

让我们看看你的代码

var obj = new ExpandoObject();
var propName = "Product";

var obj.propName = "Pie"

Console.WriteLine("Let's print!: " + obj.Product);

//OUTPUT
Let's print!: Pie

在您的代码中使用var obj = new ExpandoObject();,因此您要创建类型为ExpandableObject的静态类型对象。他们在博客中专门提到了

  

我没有写ExpandoObject contact = new ExpandoObject(),因为如果我确实联系将是ExpandoObject类型的静态类型对象。当然,静态类型的变量不能添加成员在运行时。所以我使用了新的dynamic关键字而不是类型声明,因为ExpandoObject支持动态操作,所以代码可以工作

因此,如果您重写代码以使用dynamic obj,并将动态属性添加为属性,它应该可以工作!

但是对于您的特定用例,您最好使用上面建议的@dbc

dynamic obj = new ExpandoObject();
obj.Product= "Pie"    
Console.WriteLine("Let's print!: " + obj.Product);    
//OUTPUT
Let's print!: Pie