不需要的列表修改
Unwanted list modification
我在尝试修改 foreach 中的事务列表时遇到问题。我已经创建了传递到我的方法中的列表的副本,将其设为只读,但是当我尝试更改任何列表中的值时,它会更改所有列表中的值。某种类型的记忆链接?我不确定如何解决这个问题。
我的程序首先声明一个名为 Transaction 的 class(这是一个通用的 class,具有名称、值、格式),然后我有子类:Transaction。我创建了一个 TransList(来自 public class TransList : IEnumerable),它具有每个子类的对象实例。因此,TransList 将包括一个名为 TranID、Amount、OrderID、Time、CardType、Comment1、Comment2 的 class。这些 subclasses 的每个值可以是字符串、十进制、DateTime。之后创建了一个 TransParts 列表,然后将其放入一个更大的名为 processTrans 的列表中。
所以 Comment2 是带有付款引用编号的元素,如果其中有多个编号,我想将其分成多个 TransList,将这些新的 TransList 添加到 processTrans 并删除未分开的 TransList。从我下面的代码中,尝试了所有策略后,运行时修改不仅发生在预期的 processTrans 上,还发生在 tempProcessTrans、addOn、tran、tranPart 上。
如果传递给方法的 processTrans 在调试器局部变量中看起来像这样
processTrans [0] _Items TranID.Value = SD234DF 和 Comment2 = adf;wer;
那么输出应该是
processTrans [0] _Items TranID.Value = SD234DF-1 和 Comment2.Value=adf
processTrans [1] _Items TranID.Value = SD234DF-2 和 Comment2.Value=wer
我目前得到
processTrans [0] _Items TranID.Value = SD234DF-1-2 和 Comment2.Value=wer
processTrans [1] _Items TranID.Value = SD234DF-1-2 和 Comment2.Value=wer
public static List<TransList> SeperateMultiCitations(List<TransList> processTrans) //change TransList seperating Multiple Citations
{
List<int> indexes=new List<int>();
IList<TransList> tempProcessTrans = processTrans.AsReadOnly(); //this didn't help
List<TransList> addOn= new List<TransList>(); //copy list didn't stop from changes to occur in processTrans at same time
foreach (TransList tran in tempProcessTrans.ToList())
{
TransList copyTransList = tran;
foreach (Transaction tranPart in tran.OfType<Comment2>())
{
if (new Regex(";.+;").IsMatch((string)tranPart.Value, 0))
{
string[] citations = Regex.Split((string)tranPart.Value, ";").Where(s => s != String.Empty).ToArray();
int citNumb = 1;
indexes.Add(tempProcessTrans.IndexOf(tran));
foreach (string singleCitation in citations)
{
addOn.Add(ChangeTrans(tran, singleCitation, citNumb++)); when this line runs changes occur to all lists as well as trans, tranPart
}
break;
}
}
}
foreach (int index in indexes.OrderByDescending(x => x))
{
processTrans.RemoveAt(index);
}
processTrans.AddRange(addOn);
return processTrans;
}
public static TransList ChangeTrans(TransList copyTransList, string singleCitation, int citNumb) //add ConFee
{
foreach (Transaction temp in copyTransList.OfType<TranID>())
{
temp.Value += "-" + citNumb;
}
foreach(Transaction temp in copyTransList.OfType<Comment2>())
{
temp.Value = singleCitation;
}
foreach (Transaction temp in copyTransList.OfType<Amount>())
{
//temp.Value = DboGrab(temp);
//temp.Value = amount;
}
return copyTransList;
}
public class Transaction : TranInterface
{
public string Name;
public object Value;
public string Formating;
public Transaction(string name, object value, string formating)
{
Name = name;
Value = value;
Formating = formating;
}
}
class TranID : Transaction
{
public TranID(string Name, string Value, string Formating) : base("Transaction ID", Value, "@") { }
}
public class TransList : IEnumerable<Transaction> //not to add all the lengthy parts here but this just allows for adding the parts and iterating through them in the foreach statements
{}
您看到的行为是 reference types
的固有特征。当你调用ChangeTrans()
方法时,那个方法返回的引用和你传入的完全一样,就是那个原始值tran
。在内部循环中,tran
的值永远不会改变,因此在循环的每次迭代中,您都在一遍又一遍地修改同一个对象,并在每次迭代时将其添加到 addOn
列表中。
这有两个不良影响:
addOn
列表中的每个元素之间没有区别。它们都是相同的,引用同一个对象。
- 对
addOn
列表中任何单个元素的任何修改,或通过对该单个对象的原始引用所做的任何修改,都可以通过对同一单个对象的所有其他引用看到。 IE。通过列表中的所有其他元素,甚至 tran
变量中的原始引用(当然还有 copyTranList
变量,它被分配给 tran
的值)。
如果没有更完整的代码示例,则无法确定最佳解决方案是什么。但是,一种天真的解决方案是简单地更改您的 ChangeTrans()
方法,使其负责制作新副本:
public static TransList ChangeTrans(
TransList copyTransList, string singleCitation, int citNumb) //add ConFee
{
TransList newTransList = new TransList();
foreach (Transaction temp in copyTransList.OfType<TranID>())
{
Transaction newTransaction = new TranID();
newTransaction.Value = temp.Value + "-" + citNumb;
newTransList.Add(newTransaction);
}
foreach(Transaction temp in copyTransList.OfType<Comment2>())
{
Transaction newTransaction = new Comment2();
newTransaction.Value = singleCitation;
newTransList.Add(newTransaction);
}
return newTransList;
}
注意:我不知道上面的代码是否真的可以编译,或者它是否真的复制了所有需要的值。我重申:由于您没有显示 TransList
或 Transaction
数据结构,因此无法知道需要复制其中的所有内容,也无法知道复制这些值的最佳方法是什么。
就是说,在上面的例子中注意这个版本的方法:
- 创建
TransList
对象的全新实例,将引用存储在 newTransList
中。
- 对于每个要修改的
Transaction
值,它都会创建一个全新的 Transaction
实例(使用适当的类型),分配给 that 实例的Value
属性修改后的值。
- 对于每个新的
Transaction
对象,它将对象添加到 newTransList
变量引用的新创建的 TransList
对象中。
- 最后,returns 新创建的
TransList
对象,而不是传递给方法的对象。
想必您知道将 Transaction
元素添加到 TransList
对象的正确方法是什么,以及 Transaction
对象中是否还有其他成员需要复制.以上只是一个简单的说明,说明您可以在何处以及如何修改代码,以便执行 "deep copy" 所需的操作来避免您所描述的问题。
我在尝试修改 foreach 中的事务列表时遇到问题。我已经创建了传递到我的方法中的列表的副本,将其设为只读,但是当我尝试更改任何列表中的值时,它会更改所有列表中的值。某种类型的记忆链接?我不确定如何解决这个问题。
我的程序首先声明一个名为 Transaction 的 class(这是一个通用的 class,具有名称、值、格式),然后我有子类:Transaction。我创建了一个 TransList(来自 public class TransList : IEnumerable),它具有每个子类的对象实例。因此,TransList 将包括一个名为 TranID、Amount、OrderID、Time、CardType、Comment1、Comment2 的 class。这些 subclasses 的每个值可以是字符串、十进制、DateTime。之后创建了一个 TransParts 列表,然后将其放入一个更大的名为 processTrans 的列表中。
所以 Comment2 是带有付款引用编号的元素,如果其中有多个编号,我想将其分成多个 TransList,将这些新的 TransList 添加到 processTrans 并删除未分开的 TransList。从我下面的代码中,尝试了所有策略后,运行时修改不仅发生在预期的 processTrans 上,还发生在 tempProcessTrans、addOn、tran、tranPart 上。
如果传递给方法的 processTrans 在调试器局部变量中看起来像这样
processTrans [0] _Items TranID.Value = SD234DF 和 Comment2 = adf;wer;
那么输出应该是
processTrans [0] _Items TranID.Value = SD234DF-1 和 Comment2.Value=adf
processTrans [1] _Items TranID.Value = SD234DF-2 和 Comment2.Value=wer
我目前得到
processTrans [0] _Items TranID.Value = SD234DF-1-2 和 Comment2.Value=wer
processTrans [1] _Items TranID.Value = SD234DF-1-2 和 Comment2.Value=wer
public static List<TransList> SeperateMultiCitations(List<TransList> processTrans) //change TransList seperating Multiple Citations
{
List<int> indexes=new List<int>();
IList<TransList> tempProcessTrans = processTrans.AsReadOnly(); //this didn't help
List<TransList> addOn= new List<TransList>(); //copy list didn't stop from changes to occur in processTrans at same time
foreach (TransList tran in tempProcessTrans.ToList())
{
TransList copyTransList = tran;
foreach (Transaction tranPart in tran.OfType<Comment2>())
{
if (new Regex(";.+;").IsMatch((string)tranPart.Value, 0))
{
string[] citations = Regex.Split((string)tranPart.Value, ";").Where(s => s != String.Empty).ToArray();
int citNumb = 1;
indexes.Add(tempProcessTrans.IndexOf(tran));
foreach (string singleCitation in citations)
{
addOn.Add(ChangeTrans(tran, singleCitation, citNumb++)); when this line runs changes occur to all lists as well as trans, tranPart
}
break;
}
}
}
foreach (int index in indexes.OrderByDescending(x => x))
{
processTrans.RemoveAt(index);
}
processTrans.AddRange(addOn);
return processTrans;
}
public static TransList ChangeTrans(TransList copyTransList, string singleCitation, int citNumb) //add ConFee
{
foreach (Transaction temp in copyTransList.OfType<TranID>())
{
temp.Value += "-" + citNumb;
}
foreach(Transaction temp in copyTransList.OfType<Comment2>())
{
temp.Value = singleCitation;
}
foreach (Transaction temp in copyTransList.OfType<Amount>())
{
//temp.Value = DboGrab(temp);
//temp.Value = amount;
}
return copyTransList;
}
public class Transaction : TranInterface
{
public string Name;
public object Value;
public string Formating;
public Transaction(string name, object value, string formating)
{
Name = name;
Value = value;
Formating = formating;
}
}
class TranID : Transaction
{
public TranID(string Name, string Value, string Formating) : base("Transaction ID", Value, "@") { }
}
public class TransList : IEnumerable<Transaction> //not to add all the lengthy parts here but this just allows for adding the parts and iterating through them in the foreach statements
{}
您看到的行为是 reference types
的固有特征。当你调用ChangeTrans()
方法时,那个方法返回的引用和你传入的完全一样,就是那个原始值tran
。在内部循环中,tran
的值永远不会改变,因此在循环的每次迭代中,您都在一遍又一遍地修改同一个对象,并在每次迭代时将其添加到 addOn
列表中。
这有两个不良影响:
addOn
列表中的每个元素之间没有区别。它们都是相同的,引用同一个对象。- 对
addOn
列表中任何单个元素的任何修改,或通过对该单个对象的原始引用所做的任何修改,都可以通过对同一单个对象的所有其他引用看到。 IE。通过列表中的所有其他元素,甚至tran
变量中的原始引用(当然还有copyTranList
变量,它被分配给tran
的值)。
如果没有更完整的代码示例,则无法确定最佳解决方案是什么。但是,一种天真的解决方案是简单地更改您的 ChangeTrans()
方法,使其负责制作新副本:
public static TransList ChangeTrans(
TransList copyTransList, string singleCitation, int citNumb) //add ConFee
{
TransList newTransList = new TransList();
foreach (Transaction temp in copyTransList.OfType<TranID>())
{
Transaction newTransaction = new TranID();
newTransaction.Value = temp.Value + "-" + citNumb;
newTransList.Add(newTransaction);
}
foreach(Transaction temp in copyTransList.OfType<Comment2>())
{
Transaction newTransaction = new Comment2();
newTransaction.Value = singleCitation;
newTransList.Add(newTransaction);
}
return newTransList;
}
注意:我不知道上面的代码是否真的可以编译,或者它是否真的复制了所有需要的值。我重申:由于您没有显示 TransList
或 Transaction
数据结构,因此无法知道需要复制其中的所有内容,也无法知道复制这些值的最佳方法是什么。
就是说,在上面的例子中注意这个版本的方法:
- 创建
TransList
对象的全新实例,将引用存储在newTransList
中。 - 对于每个要修改的
Transaction
值,它都会创建一个全新的Transaction
实例(使用适当的类型),分配给 that 实例的Value
属性修改后的值。 - 对于每个新的
Transaction
对象,它将对象添加到newTransList
变量引用的新创建的TransList
对象中。 - 最后,returns 新创建的
TransList
对象,而不是传递给方法的对象。
想必您知道将 Transaction
元素添加到 TransList
对象的正确方法是什么,以及 Transaction
对象中是否还有其他成员需要复制.以上只是一个简单的说明,说明您可以在何处以及如何修改代码,以便执行 "deep copy" 所需的操作来避免您所描述的问题。