在循环中创建新对象

6

我遇到了一个小的C#入门问题。但我相信这很容易解决。

foreach(var test in Tests)
{
     object testObj = new object();             
     //Do something with the object
}

如果我像那样做,每次循环对象testObj都会被覆盖。有没有可能不要每次都覆盖它? 还是必须使用数组?
编辑:好的,抱歉,我会尽量更具体: 我的目标是在此循环中创建一些对象,然后我使用每个对象调用一个新线程。在那里,我想对对象进行某些操作,完成后就释放它。
Thomas的第二次编辑:
foreach (var test in Tests)
{
     object testObj = new object();
     //Set some properties of the object
     Thread t = new Thread(() => manager(testObj));  
     t.Start();
}

public void manager(object testObj)
{
    //Do something with the object

    //Release it
}

2
是的,这是可能的。请更具体地说明您面临的问题是什么? - Ehsan Sajjad
为什么需要在数组内创建对象? - Andrew
他们不会。但是当我不再使用它们时,C#不应该自动处理吗? - xileb0
@xileb0 通常是这样的,只是垃圾回收器不会立即释放它们(需要牢记这一点)。有办法绕过这个问题(这里有几个问题是关于这个的)。另外,像特定图像对象这样的某些对象存��问题,需要采取额外的步骤才能使垃圾回收器释放它们(遇到过这些问题,总是问自己一个问题:“为什么???”....从来没明白为什么 c# 的一些操作需要做这些不一致的事情) - Thomas
请自动释放没有内存的情况下未被GC处理的.NET Bitmap图像。 - Thomas
显示剩余6条评论
2个回答

7

你面临的问题有两个。

  1. 变量的生命周期。局部变量只在其定义的块中存在。因此,你在foreach循环内定义了testObj。这意味着它只在块的一次迭代中存在,并在循环结束时结束生命。下一次迭代会有一个新的testObj。

因此,

object testObj 

foreach(var test in Tests)
{
     testObj = new object();             
     //Do something with the object
}

由于testObj在循环外定义,因此无论迭代多少次,它都保留着设定的值。

然后

  1. 您总是重新设置它。如果将变量设置为新值,则旧值将被新值覆盖。因此,如果要保存创建的每个testObj,则必须使用列表、数组等(或者为每个testObj使用1个变量,但通常只有完全初学者才会这样做。仅提及这一点是为了完整起见,并提到这不是应该做的事情,因为它会大大增加开销)。

所以,您可以这样做:

List testObjList = new List();

foreach (var tests in Tests)
{
    testObjList.Add(new object());
    // Or alternatively  object testObj = new object();  testObjList.Add(testObj);
}

如果你直接将它添加到列表中(Add(new object)),则可以通过 testObjList[testObjList.Count - 1] 访问它(由于索引以0而不是1开始,因此索引为count-1)。这与使用第二种变量的testObj相同。
编辑: 要在线程内使用它们,然后消除这些对象,您有两个选项。
1.)如果该对象没有任何处理功能,则原始代码就可以了。
foreach(var test in Tests)
{
     object testObj = new object();             
     //Do something with the object
}

当代码块结束时,对象会丢失,但垃圾回收器决定何时真正删除它(有一些例外情况,如图像,可能需要执行特殊操作才能删除它们)。

如果您的对象属于特定类(我们称之为myobject以避免与普通对象混淆),并且具有dispose功能,则可以使用该功能:

foreach(var test in Tests)
{
     using (myObject testObj = new myObject())
     {             
         //Do something with the object
     }
}

这意味着myObject对象仅在using块内存在,并且当块结束时(即使是通过异常),都会执行dispose部分,这应该确保垃圾收集器能够释放内存。

我不认为我的原始代码很好 :( 因为当我第二次通过循环时,第一个对象总是会丢失。 - xileb0
@xileb0,看一下问题1,那就是变量的生命周期。如果你在一个块内定义了一个变量,它只在该块执行期间有效/存活一次,然后会被重新创建(在循环块的情况下)。这里有一些关于这个主题的信息:https://msdn.microsoft.com/en-us/library/aa691170(v=vs.71).aspx。 - Thomas
我理解你的意思了。就像我评论中所说,那应该能够正常工作。你提供的对象是通过引用传递的:https://dev59.com/dGcs5IYBdhLWcg3wRBxQ 这意味着对对象本身所做的更改在内部和外部都是一致的。在您的情况下,在下一个循环中将变量设置为新值不会影响在线程内使用的对象。到目前为止,可以认为它们是两个不同的对象。 - Thomas
下一个循环创建的对象与上一个循环中存在于线程内的对象不同。 - Thomas
@xileb0 刚刚想到一个可能性。你在聊天中发送给我的代码中使用了.instance。.instance是指静态的(静态变量或方法,或者返回静态变量的方法)吗? - Thomas
显示剩余7条评论

3

每次迭代创建新实例是完全可以的,因为该对象仅在一个生命周期中使用。因此,您创建的每个线程都会获得自己的testObj实例。如果您想要在循环之后对对象执行任何操作,则必须缓存它,可以使用数组或列表缓存每个实例,或者在循环之前使用object testObject来缓存最后一个实例,并在每次迭代时重新赋值。然而,这将导致引用testObject仅包含您在最后一次迭代中创建的最后一个实例。

object testObj;
foreach (var test in Tests)
{
     testObj = new object();  // creates a new instance every iteration
     //Set some properties of the object
     Thread t = new Thread(() => manager(testObj));  
     t.Start();
}

// do anything with the lastly created instance
DoSomething(testObject);

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