2
if (!someList.Contains(new listItem(arg1, args2)))
{
    // Do some stuff
}

对于上面的代码段,someList是一个结构体列表,listItem是结构体。

在这种情况下使用 new 运算符会导致内存泄漏吗?或者这是一般不良做法的一个例子?我在 SO 和 Google 上进行了搜索,但找不到专门解决此问题的问题。

4

4 回答 4

6

您必须非常努力地在 C# 中创建内存泄漏。这是可能的,但它意外发生的情况并不多(除了与没有如此简单的内存管理的其他语言进行互操作时)。不过,我不会在这里讨论边缘情况。

以下是该对象的内存外观:

  • 将在保存您显示的代码的任何方法中创建一个局部变量。由于您没有将新结构显式设置为局部变量,因此它将具有一些无法在代码中引用的名称。
  • 它将通过堆栈传递给您调用的方法。(它将按值传递,因此此时将有两个具有相同结构的变量)。
  • Contains返回它的调用堆栈上的参数将被“释放”,所以我们现在回到只有一个变量。
  • 当您当前使用的方法完成时(或者可能更早一点,如果编译器想要优化它,知道它不再使用),结构的堆栈空间将被“释放”

即使new使用了关键字,也不会在堆上创建结构。它仍然在堆栈上创建。在 C#new中显式调用任何构造函数时使用(禁止反射)并且不指示堆上的分配(它在 C++ 中的方式)。

还值得一提的是,即使这是一个类而不是结构,也不会导致任何内存泄漏。该对象最终会在堆上,但垃圾收集器会在不再需要它之后的某个时候清理它。您在这里没有做任何会导致在不需要对象时保留对对象的引用的事情(而且我知道这Contains不会做任何会阻止它被收集的恶作剧;如果它是一些未知的功能,它就是可能但不太可能他们会做一些有意义的事情)。

于 2012-08-31T18:10:53.357 回答
3

这与结构有关并不少见。例如,在使用DateTimes 时,说起来更易读:

if (fooDate == new DateTime(2000, 1, 30, 11, 30, 0))

if (fooDate.Year = 2000 && fooDate.Month = 1 && fooDate.Day = 30 && ...)
于 2012-08-31T18:18:37.540 回答
2

这不是内存泄漏,我也没有必要称之为坏风格(它在 MSDN示例用法中使用)

但可能不是我会这样做 - 我会做类似的事情:

if (!someList.Any(o => o.Arg1 == arg1 && o.Arg2 == arg2)) 
{ 
    // Do some stuff 
} 
于 2012-08-31T18:05:12.053 回答
1

这是可读性的问题。我发现像你展示的那样完成后更难阅读我更喜欢单独声明列表

性能或内存泄漏没有差异

此外,当您单独声明一个列表时,您可以给您的列表一个有意义的名称

例如 var listOfDays = 新列表.....

于 2012-08-31T18:02:30.257 回答