不需要的列表修改

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 列表中。

这有两个不良影响:

  1. addOn列表中的每个元素之间没有区别。它们都是相同的,引用同一个对象。
  2. 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;
}

注意:我不知道上面的代码是否真的可以编译,或者它是否真的复制了所有需要的值。我重申:由于您没有显示 TransListTransaction 数据结构,因此无法知道需要复制其中的所有内容,也无法知道复制这些值的最佳方法是什么。

就是说,在上面的例子中注意这个版本的方法:

  1. 创建 TransList 对象的全新实例,将引用存储在 newTransList 中。
  2. 对于每个要修改的 Transaction 值,它都会创建一个全新的 Transaction 实例(使用适当的类型),分配给 that 实例的Value 属性修改后的值。
  3. 对于每个新的 Transaction 对象,它将对象添加到 newTransList 变量引用的新创建的 TransList 对象中。
  4. 最后,returns 新创建的 TransList 对象,而不是传递给方法的对象。

想必您知道将 Transaction 元素添加到 TransList 对象的正确方法是什么,以及 Transaction 对象中是否还有其他成员需要复制.以上只是一个简单的说明,说明您可以在何处以及如何修改代码,以便执行 "deep copy" 所需的操作来避免您所描述的问题。