2015-01-08 50 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'中。 –