创建一个匿名类型数组。

4

我正在尝试从数据库中获取数据为我的程序中的谷歌图表服务。我想创建一个匿名类型数组(var),而不是一遍又一遍地重复我的代码:

 public JsonResult GetChartData(int sID, int regionID)
    {

            var testPathOne = from p in _rep.GetMetricsData().GetLHDb().page_loads                                 
                              where p.t_3id == sID && p.test_path_id == 1
                              select new { time = p.time, created_at = p.created_at };

            var testPathTwo = from p in _rep.GetMetricsData().GetLHDb().page_loads
                              where p.t_3id == sID && p.test_path_id == 2
                              select new { time = p.time, created_at = p.created_at };

            var tOne = testPathOne.ToArray();
            var tTwo = testPathTwo.ToArray();
            var name = new { test1 = tOne, test2 = tTwo };
            return Json(name);
        }

我知道我需要一个for循环,这样我就可以遍历所有的测试路径ID,而不是像这样硬编码它们: p.test_path_id == 1,但我的问题是如何使这部分动态化:var name = new { test1 = tOne, test2 = tTwo };

编辑:我很抱歉,我想做这样的事情:

name is an array

for loop:
    testPath = query
    name.Add(testPath)

我希望你能理解。

我希望这样说得通


6
“使这一部分变得动态”是什么意思?以何种方式动态?你试图实现什么并不清楚。如果你想要动态属性名称,可以考虑使用ExpandoObject,但我认为直接构建JSON可能更好... - Jon Skeet
1
我不理解这个问题。只是为了再次确认,var 只能在编译器可以完全确定 var 所代表的类型的情况下使用。如果类型直到运行时才能确定,您可能需要考虑使用 dynamic,但我不确定它如何适用于这种特定情况。 - sblom
我认为他想要将这两个列表返回为一个单一的JSON。 - Asif Mushtaq
1
为什么不创建一个包含“时间”和“创建时间”的简单结构体呢?这样你就可以知道类型并使你的代码更易读和可维护。 - Nick Babcock
你的意思是循环遍历“test_path_id”的值,然后构建JSON,类似于{"test1"={}, "test2"={},...., "test1234"={}}吗? - Alexei Levenkov
显示剩余2条评论
2个回答

4
在这种特定情况下,最简单的解决方案是为目前匿名的类赋予一个名称。虽然你可以使用一些变通方法,但如果你需要努力地使用匿名类型,那么你可能不应该使用它。它存在的目的是使某些任务更快、更容易完成;如果这一目的未能实现,那么你很可能应该使用一个真正的类。
该解决方案的代码如下:
//Please give me a real name
public class ClassToBeRenamed
{
    public DateTime Time { get; set; }
    public DateTime CreatedAt { get; set; }
}

List<ClassToBeRenamed[]> myList = new List<ClassToBeRenamed[]>();

for (int i = 0; i < 10; i++)
{
myList.Add((from p in _rep.GetMetricsData().GetLHDb().page_loads
            where p.t_3id == sID && p.test_path_id == i
            select new ClassToBeRenamed { Time = p.time, CreatedAt = p.created_at })
            .ToArray());
}

说了这么多,仍然有可能实现。
var myList = new[]{
                from p in _rep.GetMetricsData().GetLHDb().page_loads
                where p.t_3id == sID && p.test_path_id == 1
                select new { time = p.time, created_at = p.created_at }.ToArray()
}.ToList();

for (int i = 2; i < 10; i++)
{
    myList.Add(from p in _rep.GetMetricsData().GetLHDb().page_loads
                where p.t_3id == sID && p.test_path_id == i
                select new { time = p.time, created_at = p.created_at }.ToArray()
                );
}

var myArray = myList.ToArray();

如果你确实非常重视数组而不是列表,那么你可以在最后调用myList的ToArray方法。但是要注意,在开始时使用列表,并且只在最后将其转换为数组,因为一旦创建了数组,它的大小就是固定的。你可以改变它们的内容,但不能让它们变得更大或更小。另一方面,列表被设计为可以随着时间的推移而改变大小,因此它可以从0或1个项目开始,然后随着时间添加项目,在这种特定的情况下非常重要。实际上,这经常很有用,这就是为什么频繁地使用列表而不是数组的原因。

你把两个不同的列表混合在一起了,这并不是期望的结果。 - Asif Mushtaq
再次感谢。是的,对我来说有一个数组很重要。因此我添加了ToArray而不是ToList,但是它说数组不包含Add函数的定义。我该如何解决这个问题? - SherCoder
你需要在最后将它从列表转换为数组,而不是在开始时。我会在答案中详细解释原因。 - Servy
谢谢,但我的另一个问题是,如果我想做这样的事情:testPaths.Add(test1= myquery)。 - SherCoder
我想给它一个名称,就像我在这里做的一样:var name = new { test1 = tOne, test2 = tTwo }; - SherCoder
显示剩余3条评论

2

不要使用LINQ,而是使用foreach循环。你在使用LINQ时的限制更多。 同时在开始时定义你的ArrayLists,并随着操作的进行添加元素。

var test1 = new ArrayList();
var test2 = new ArrayList();
foreach(PageLoad p in _rep.GetMetricsData().GetLHDb().page_loads)
{
    if(p.t_3id == sID)
    {
        var tr = new { time = p.time, created_at = p.created_at };
        switch(p.test_path_id) 
        {
            case 1: test1.Add(tr); break;
            case 2: test2.Add(tr); break;
        }
    }
}
return Json(new { test1, test2, });

您不需要定义匿名类型的属性名称,因为它们默认为变量名称。


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