据我所知,当你使用引用类型作为方法中的参数时,会复制堆栈上的值,因此形式参数指向堆上的相同内存地址因此,一旦完成该方法,更改将保持不变。
这如何处理任务?我刚刚创建了2个新任务并传入了一个在UI线程上声明的数组。其中一个新任务所做的更改立即显示在第二个任务中。当我尝试通过UI线程更改输入(数组)时,相同的参数在2个新任务上没有改变。它应该有它的印象,因为它们都应该指向堆上的相同内存位置?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace TasksAndMemory
{
class Program
{
private static ManualResetEvent mre = new ManualResetEvent(false);
static void Main(string[] args)
{
int[] readToEnd = new int[2];
int[] data = new int[] { 1, 2, 3, 4, 5, 6 };
int valueType = 5;
int pageCounter = 1;
Task[] tasks = new Task[2];
for (int x = 1; x < 3; x++)
{
//Needed due to closure problem
int i = x;
tasks[i-1] = Task.Factory.StartNew(() =>
{
SpecialMethod(data, readToEnd, i, valueType);
});
}
while(pageCounter < 4)
{
if (readToEnd[0] == 1 && readToEnd[1] == 1)
{
//Sets the state of the event to nonsignaled, causing threads to block
mre.Reset();
int[] temp = new int[] { 7, 8, 9, 10, 11, 12 };
data = temp;
readToEnd[0] = 0;
readToEnd[1] = 0;
//Sets the state of the event to signaled, allowing one or more waiting threads to proceed.
mre.Set();
pageCounter++;
}
}
Console.ReadLine();
}
public static void SpecialMethod(int[] historicalData, int[] readToEnd, int taskNumber, int valueTy)
{
int[] temp = new int[] { 100, 200, 300, 400, 500, 600 };
for (int x = 0; x <= historicalData.Length; x++)
{
if (x == historicalData.Length)
{
readToEnd[taskNumber-1] = 1;
mre.WaitOne();
x = 0;
}
else
{
valueTy++;
temp[x] = temp[x] + taskNumber;
}
}
}
}
}
答案 0 :(得分:2)
您创建一个数组:
int[] data = new int[] { 1, 2, 3, 4, 5, 6 };
然后将引用的副本传递给此数组(当前存储在data
中)作为SpecialMethod
的参数(通过捕获原始代码,但不重要,它仍然只是一个副本。)
在SpecialMethod
内,参数int[] historicalData
将收到对此原始数组的引用的副本。
此后,导致变量data
被重新分配的任何内容(与data
引用引用的数组中的数据所做的更改相反)对任何<没有影响<由原始引用构成的em>副本 - 它们仍然引用原始数组。
我不清楚你在线程之间传递数据的实际要求是什么,所以我不能提出任何坚定的建议。我通常会尽量避免使用原始数组。
答案 1 :(得分:1)
您的分析在开始时似乎是正确的,但您的结论不是。
您有一个引用类型(数组),并将它传递给一个按值的方法(这是默认值)。这意味着对位于堆上的该数组的引用是复制。
由于SpecialMethod
和Main
中的变量都具有相同的引用,因此更改它们引用的值将被两个变量“看到”。
仅当您 mutate 数组时才适用。这就是你用readToEnd
做的事情,这就是处理它的代码部分按你的意图工作的原因。
另一方面,data
不会改变数组,只需为变量分配一个新数组。这正在改变引用,而不是它引用的对象,这就是你遇到问题的原因。
至于解决方案,有几个。首先,您可以更改代码以改变数组而不是分配新数组;只是改变现有的价值观。如果您需要更改元素数量,请考虑使用List
而不是数组。
另一种选择是,不是传递数组,而是添加另一层间接。您可以创建一个具有属性数组的新类,将该类型的对象传递给SpecialMethod
,然后您可以更改该对象的属性并在两个位置看到它。您可以使用类似的内容来涵盖一般情况:
public class Wrapper<T>
{
public T Value { get; set; }
}