2015-01-08 51 views
0

我试图修改foreach中的事务列表时遇到问题。我创建了传递给我的方法的列表的副本,使其成为只读的,但是当我尝试更改任何列表中的值时,它将更改其中的值。某种类型的记忆链接?我不确定如何解决此问题。我的程序从声明一个名为Transaction的类(它是一个具有Name,Value,Formatting的泛型类)开始,然后我有子类:Transaction。我创建了TransList(来自公共类TransList:IEnumerable),它具有每个子类的对象实例。所以TransList将包含一个名为TranID,Amount,OrderID,Time,CardType,Comment1,Comment2的类。这些子类的每个值都可以是字符串,小数点,日期时间。之后,创建TransParts列表,然后将其放入名为processTrans的更大列表中。不需要的列表修改

所以Comment2是带有付款引用号码的元素,如果在那里有多个数字,我想将它分隔成多个TransList将这些新的TransLists添加到processTrans并删除未分离的一个。从我的代码中,尝试了所有的策略,运行时修改不仅发生在预期的processTrans上,而且发生在tempProcessTrans,addOn,tran,tranPart。

如果传递到方法processTrans看起来像这样在调试器当地人
processTrans [0] _items TranID.Value = SD234DF和注释2 = ADF; WER;
然后输出应为
processTrans [0] _items TranID.Value = SD234DF-1和Comment2.Value = ADF
processTrans [1] _items TranID.Value = SD234DF-2和Comment2.Value =疫情周报
我目前得到
processTrans [0] _items TranID.Value = SD234DF-1-2和Comment2.Value =疫情周报
processTrans [1] _items TranID.Value = SD234DF-1-2和Comment2.Value =疫情周报

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 
{} 
+0

您可以显示构建这些对象的代码并将它们添加到原始列表中吗? –

+0

您并未创建对象的新实例,因此您在ChangeTrans中的修改发生在原始类上。如果我的问题是正确的,那么在处理每个项目时,它将根据正则表达式的结果转换为一个或多个项目?如果你用更多关于结构的信息来重构问题,你可能会得到更好的答案。 –

+1

TransList copyTransList = tran;不会复制'tran'。它仅为tran创建了另一个参考。你想要一个深度拷贝。这通常是通过构造一个构造函数来完成它自己的类型的对象,然后复制所有的值。 – MrFox

回答

3

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

这有两个不希望的效果:

  1. 有一个在addOn列表中的每个元件之间没有差别。它们都是相同的,引用相同的单个对象。
  2. addOn列表中的任何单个元素或通过对该单个对象的原始引用进行的任何修改都可通过对该同一单个对象的其他引用来查看。即通过列表中的所有其他元素,甚至是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; 
} 

注:我也不知道,如果上面居然会编译,或者如果它实际上会将所有所需的价值。我重申:由于您没有显示数据结构,因此无法知道其中的所有内容都需要复制,也不可能知道复制这些值的最佳方式。

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

  1. 创建TransList对象的完全新的实例,存储newTransList参考。
  2. 对于每个Transaction值被修改时,它创建的Transaction一个全新的实例(使用适当的类型),分配给该实例的Value属性修改后的值。
  3. 对于每个新的Transaction对象,它将该对象添加到由newTransList变量引用的新创建的对象TransList
  4. 最后,它返回新创建的TransList对象,而不是传递给该方法的对象。

想必你知道什么是正确的方法来Transaction元素添加到TransList对象,以及是否有在Transaction对象,将需要复制的其他成员。以上只是一个简单的例子,说明你在哪里以及如何修改你的代码,以便你可以做“深层复制”来避免你描述的问题。

+0

我明白你的答案,但我的问题是,那么我是否会在TransList中有两个不同的TranID副本?因此需要先删除旧的。 – Edward

+0

或重读我认为你只是让我在这个方法中创建一个全新的TransList然后传回给它?当然,这是真的,我需要创建每个事务的子类,并将其添加到此处的新TransList中。正确? – Edward

+0

你理解我写的例子代码。不幸的是,你的原始代码不够完整,我不能真正理解实际需要什么。我只能说,任何想要修改而不影响现有实例的对象,都需要在修改对象之前创建对象的副本(或从头开始创建一个新的对象)。您将“TransList”对象添加到一个全新的列表中,这可能意味着您可能需要一个全新的“TransList”对象。注意如果你不创建一个新的列表,这意味着新的,修改后的对象将被添加到你原来的'TransList'中。 –