性能命中?匿名类型的列表以在 c# 中实现类似 List<int, string, ...>(多种类型的多维列表))

Performance Hit? list of anonymous type to achieve something like this List<int, string, ...> (a multi-dimensional list of multiple types) in c#)

我想知道创建匿名类型列表是否是有效创建多种类型列表的最佳方式,以及它对一般性能和效率的影响。主要是想知道有没有更标准的List做法?

情况 我时不时地发现自己需要创建一个列表,其中每个值都有不同类型的列表。通常我会用字典来解决这个问题,但在某些情况下我不关心重复的键值或需要第三个(或很少是第四个)值。通常这是用于临时列表,它只跟踪方法中包含的某些内容,例如记录抛出的错误和关联值,以便在方法结束时我可以将消息串在一起用于日志文件或其他内容。

我目前的情况是这样的:

var list = new[] { new { RowNumber = 1, Message = "" } }.ToList();
list.Clear();//clears out the example used to create the anonymous type
list.Add(new { RowNumber = 10, Message = "bla bla" }); //adding to the list

我正在考虑做一些像扩展之类的事情或者做一些让这更容易的事情,但是如果性能很糟糕或者有更好的方法,我想知道。

我更喜欢class。 IL 只是在本机中创建一个匿名 class,其调用方式与普通 class 相同,因此不会影响性能。如果你曾经调试过匿名类型,你会注意到这个名字有一个很长的名字,比如 AnonymousTypes.Program+f__1

创建 class 可以提高代码 IMO 的可读性。

public class RowMessage
{
    public int RowNumber { get; set; }
    public string Message { get; set; }
}

你也可以使用元组,但即使这样仍然不清楚:

    public void MyMethod()
    {
        Tuple<int, string> myTuple = new Tuple<int, string>(1, "hi");
        List<Tuple<int, string>> myTupList = new List<Tuple<int, string>>();
        myTupList.Add(myTuple);
    }

我刚刚experimented a little。这是我的发现:

  • 匿名类型和其他类型一样好。我不能真的说"anything,"因为我没有尝试一切。但我可以告诉你,它们与 Tuple<> 和具体类型一样好。这是合乎逻辑的,因为在幕后,编译器实际上为匿名类型构建类型。本质上,在运行时,它们只是具体类型。
  • 您的 ToList 调用是多余的。 这部分很重要。它与您的直接问题并没有太大关系,但是看看您的示例,您会 new [] { ... }.ToList()。这会在创建数组后强制循环遍历该数组。使用列表初始化会更好:new List<dynamic> { ... };。这就是我在示例中使用的内容。

我 运行 每次测试 10,000 次:

  • 带数组初始值设定项的匿名类型(总计 00:00:00.0050338)
  • 带列表初始值设定项的匿名类型(总计 00:00:00.0035599)
  • 带列表初始化器的元组(总计 00:00:00.0025857)
  • 带有列表初始值设定项的具体类型(总计 00:00:00.0041538)

运行 他们又会搞混。唯一一致的结果是,不出所料,数组比直接访问列表要慢。


如果您要制作扩展方法,您可能希望使用后两个选项之一。匿名类型不能很好地超出其范围,我相信您知道。具体类型和元组之间的选择是你的。如果你在原始方法之外经常使用它 and/or,我会选择具体的,如果它只需要存在于某个地方,我会选择一个元组。这真是我无法为你做出的设计选择。

由于您在谈论丰富异常信息,因此值得一提的是,异常类实现了一个名为 Data 的 属性,它属于 IDictionary 类型,可用于附加附加信息。

    try
    {
        throw new FileNotFoundException{ Data ={ { "TEST", "Hello World" } } };
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Data["TEST"]);
        ...
        e.Data.Add("Whatever", DateTime.Now);
    }

如果您发现自己多次添加相同的信息,请考虑一些将特定信息添加到给定异常的 HelperMethods。这也可以处理重复的键,这些键使用某种递增的数字后缀,如 fileName_1 等等,你明白了。 您还可以创建一个标准化的方法来输出您自己提供的那些信息。


如果您想要更复杂的方法,您可以简单地使用 List,但让此列表的使用者处理每种类型。这基本上就是 DebuggerTypeProxy-Atrribute

背后的想法

所以你可以使用这样的模式:

foreach(var typeGroup in additionalInformation.GroupBy(item => item.GetType())
{
    ITypedLogHandler handler = GetHandlerFor(typeGroup.Key);
    handler.WriteLog(typeGroup);
}

总的来说,我认为整个想法有效的唯一原因是一些方便的 debuggint/loggin 方法。其他任何东西都应该真正使用强类型。