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

3
我正在尝试创建一些动态的 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获得的信息建立连接字符串),因此我不知道需要获取什么数据。这可能是一个数据库表的示例:
TABLE Sale - ID: int, - Product: nvarchar(100), - Days: int, - QTY: bigint
这可能是另一个示例:
TABLE Foobar - Id: int, - Days: int, - QTY: 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

有人有解决方案或者简单的指导结构,可以解决这种情况吗?

你使用的是什么编程语言?你标记了C#,但你的一些代码是Java(例如System.out.printline)- .NET没有这个。 - Ahmed ilyas
我建议远离ExpandoObject,转而使用反射实现。这样可以通过从DB-Reader中获取属性名,在运行时创建整个类。 - KarmaEDV
@KarmaEDV 反射?从未使用过?你能指导我一个解释这是什么的链接吗? - Detilium
1
只需创建一个 List<Dictionary<string, object>>。如果你使用 Json.NET 将其序列化为 JSON,你将得到你想要的结果。 - dbc
2
@GSerg 你是指哪个 ExpandoObject :) - Patrick Hofman
显示剩余3条评论
5个回答

9

不必创建一个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}]

在我的情况下,这并不适用,因为我没有所有的值,但我需要循环遍历它们。你能给个例子吗?var valueList = allRowValuesvar clumn = allClumnNames(正在编辑主问题)。 - Detilium
如果创建字典后无法添加数据,那么它们将变得相当无用。 - GSerg
1
@dbc 由于某些原因,我的Json看起来像这样:[{\"ID\":1,\"Product\":\"Honning\",\"Days\":1,\"QTY\":65}] - Detilium
1
@Detilium - 这个问题中没有提到Postman,所以我不确定这是什么意思 -- 你的问题中有 Console.WriteLine()。但是如果你在某种方式下发布了它,你可能会以某种方式双重序列化你的JSON - dbc
2
@dbc 我进行了双重序列化。现在一切都正常了。谢谢你在这里花时间。我真的非常感激。 - Detilium
显示剩余3条评论

1
当我写回答的时候,我看到你已经得到了正确的答案。你可以使用一个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;
}

答案使用示例:

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));

1

正如您在ExpandoObject类中所看到的,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);

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的答案可能更适合问题(实际上不是问题)。

0

首先,彻底阅读由C#团队发布的这篇博客文章

让我们来看看你的代码

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();,因此你创建了一个静态类型为ExpandoObject的对象。在博客中他们特别提到:

我没有写ExpandoObject contact = new ExpandoObject(),因为如果我这样做,contact将成为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

他的代码和你的代码都不能工作。它们甚至无法编译。当你通过删除不需要的 var 和添加缺失的 ; 来使它们编译时,你会发现它并没有按照你预期的那样运行,并抛出了异常,而不是输出 "Pie"。因为这段代码是将属性 propName 添加到 obj 上,而不是属性 Product - GSerg
c**p,我发现问题只是静态类型的。我会编辑我的答案来修复它们。目前我无法访问Visual Studio,我来到SO寻找其他东西时看到了这个问题! - Adarsha

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接