不需要的列表修改

时间:2015-01-08 15:49:04

标签: c# list foreach ilist reference-type

我在尝试修改foreach中的事务列表时遇到问题。我创建了传递给我的方法的列表的副本,使其只读,但当我尝试更改任何列表中的值时,它会更改其中的所有值。某种类型的内存链接?我不确定如何解决这个问题。

我的程序首先声明一个名为Transaction的类(这是一个具有Name,Value,Formatting的泛型类),然后我有subClasses:Transaction。我创建了一个TransList(来自公共类TransList:IEnumerable),它有一个每个subClass的对象实例。因此,TransList将包含名为TranID,Amount,OrderID,Time,CardType,Comment1,Comment2的类。这些子类的每个值可以是字符串,十进制,DateTime。之后创建一个TransParts列表,然后将其放入一个名为processTrans的更大列表中。

因此,Comment2是具有付款引号的元素,如果有多个号码,我想将其分成多个TransList,将这些新的TransLists添加到processTrans并删除未分离的号码。从下面的代码中,尝试了每个策略后,运行时修改不仅发生在预期的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
 {}

1 个答案:

答案 0 :(得分:3)

您所看到的行为是reference types的固有特征。当您调用ChangeTrans()方法时,该方法返回的引用与您传入的引用完全相同,即原始值tran。在内部循环中,tran的值永远不会改变,因此在循环的每次迭代中,您反复修改同一个对象,并在每次迭代时将其添加到addOn列表中。

这有两个不良影响:

  1. addOn列表中的每个元素之间没有区别。它们都是相同的,引用相同的单个对象。
  2. addOn列表中任何单个元素的任何修改,或者通过对该单个对象的原始引用的任何修改,都可以通过对该同一个对象的每个其他引用来显示。即通过列表中的所有其他元素,甚至是tran变量中的原始引用(当然还有copyTranList变量,该变量已分配给tran的值)。
  3. 如果没有更完整的代码示例,就无法确定最佳解决方案是什么。但是,一个天真的解决方案是简单地更改您的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数据结构,就不可能知道它们中的所有数据都需要复制,也不知道复制这些数据的最佳方法是什么。< / p>

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

    1. 创建TransList对象的全新实例,将引用存储在newTransList中。
    2. 对于要修改的每个Transaction值,它会创建一个全新的Transaction实例(使用适当的类型),并为分配实例的Value属性修改后的值。
    3. 对于每个新Transaction个对象,它会将对象添加到TransList变量引用的新创建的newTransList对象中。
    4. 最后,它返回新创建的TransList对象,而不是传递给方法的对象。
    5. 据推测,您知道向Transaction对象添加TransList元素的正确方法,以及Transaction对象中是否还有其他成员需要复制。以上只是您可以在何处以及如何修改代码的基本说明,以便您执行所需的“深层复制”以避免您所描述的问题。