2010-11-15 34 views
0

在我的代碼中,我有一個類,它維護着許多列表。我們現在將關注其中的一個,因爲這是突出顯示問題的一個。對象來自列表<T>似乎是副本,而不是參考

internal List<Badge> Badges { get; private set; } 

在代碼中,當解析XML文檔時,我將Badge實例添加到此列表中。稍後,我想更新列表中的各個實例,以便將數據寫回XML。由於數據的XML結構與原始文件結構有所不同,因此涉及到一些重點問題,但這很大程度上已經被繪製出來。當我嘗試更新List<Badge>中的一個項目時,出現了意外。

具體來說,有問題的代碼是在這裏:

// Get the current badge from the loaded XML data, so we can update it. 
var currentBadge = this.GameData.GetCurrentBadge(); 

我總是得到一個有效的徽章回來。令人驚訝的,因爲我是來看看,就是這個簡單的測試總是失敗:

var result = this.GameData.Badges.IndexOf(currentBadge); 

result始終計算爲-1,表明該對象不集合中存在。 (編輯:更新currentBadge上的屬性對this.GameData.Badges中的匹配項目的內容沒有任何影響。)這導致我得出結論我得到我的對象的副本,而不是一個參考,因爲我會預期。

對於好奇,從GameData類檢索徽章的代碼包含在下面。我懷疑這是通用列表的記錄行爲,而且這是我第一次偶然發現它。如果是這樣,我進入一個非常粗魯的覺醒。如果不是這樣,我真的很想知道爲什麼我的物體會從原來的「斷開」回來。

private Badge GetCurrentBadge() 
{ 
    var badgeItem = GetCurrentBadgeItem(); 
    if (badgeItem != null) 
    { 
     return this.GameData.GetBadgeByText(badgeItem.Text); 
    } 
    return null; 
} 

private MenuOption GetCurrentBadgeItem() 
{ 
    if (!(this.currentItem is MenuOption && 
     (this.currentItem as MenuOption).IsLocked)) 
    { 
     return null; 
    } 

    MenuOption result = null; 
    var children = this.currentMenu.Children; 

    for (var n = children.Count - 1; n >= 0; n--) 
    { 
     var child = children[n] as MenuOption; 
     if (child == null || !child.IsLocked) 
     { 
      break; 
     } 

     if (!child.Text.StartsWith(" ")) 
     { 
      result = child; 
      break; 
     } 
    } 

    return result; 
} 

更新:每個請求,GetBadgeByText,它來自GameData類。正如你所看到的,我已經嘗試過使用Linq和不使用Linq,只是爲了消除這個罪魁禍首。改變執行方式沒有什麼意義。

並且爲了記錄,此應用程序中的所有對象都是CLASSES。沒有任何結構。

更新#2:徽章類。

internal class Badge 
     : GameDataItem 
{ 
    public Badge() 
     : base() 
    { 
    } 

    public string AuthId { get; set; } 

    public string Category { get; set; } 

    public string Description { get; set; } 

    public bool IsAccoladePower { get; set; } 

    public string RequiredBadges { get; set; } 

    public override string ToString() 
    { 
     return Text; 
    } 

    internal string ToXml() 
    { 
     var template = "<Badge value=\"{0}\" title=\"{1}\" category=\"{2}\" authid=\"{3}\" requires=\"{4}\" accolade=\"{5}\" description=\"{6}\" />"; 
     return string.Format(template, 
      this.Value, 
      this.Text, 
      this.Category, 
      this.AuthId, 
      this.RequiredBadges, 
      this.IsAccoladePower, 
      this.Description); 
    } 
} 

以防萬一有人需要它,基類:

internal class GameDataItem 
{ 
    private string _text; 
    public string Text 
    { 
     get 
     { 
      return this._text; 
     } 
     set 
     { 
      this._text = value.Replace("&lt;", "<") 
         .Replace("&gt;", ">") 
         .Replace("&amp;", "&"); 
     } 
    } 
    public string Value { get; set; } 
    public override string ToString() 
    { 
     return Text + "=\"" + Value + "\""; 
    } 
} 
+0

GetBadgeByText的外觀如何? – MarkPflug 2010-11-15 20:08:43

+0

'this.GameData.GetBadgeByText'在做什麼? – 2010-11-15 20:09:01

+1

「徽章」是結構還是類? – dtb 2010-11-15 20:09:12

回答

1

在我看來這樣的事做與MenuOption的實施Equals(object)。當決定返回什麼時,List<>IndexOf()方法將使用Equals(object)

+0

我沒有重寫任何人的Equals實現。 – 2010-11-15 20:20:58

+0

你可能實際上碰到了頭上的釘子。我爲Badge.Equals寫了一個覆蓋,並且IndexOf現在返回一個有效的索引。現在的問題是,當我更新其屬性時,currentBadge的更新會反映在集合中嗎? – 2010-11-15 20:41:18

+0

成功。我永遠不會想到Equals是罪魁禍首。榮譽,好先生。榮譽。 – 2010-11-15 20:43:10

1

或者:

  1. 你把對象的副本列表中。 (List<T>不克隆對象或做任何其他類型的欺騙。)
  2. Badge是一個結構,而不是一個類,這意味着你實際上不持有對它的引用,因爲它將是一個值類型。
  3. 在你沒有粘貼的代碼的其他地方有一些複製。
0

通用列表<T>不會複製對象。您添加對它的引用,並且出現相同的引用 - 所以代碼中必須存在另一個問題。

GetBadgeFromText如何實現?它是否直接從Badges列表中讀取?

這是一個網絡應用程序?如果是的話,您的List是否在請求之間生存,或者是否對每個請求進行反序列化和序列化(這也可能是問題)。

+0

GetBadgeByText最初使用LINQ從列表中選擇匹配的徽章;當我被這種行爲困擾時,我改變了它使用一個簡單的foreach。沒有觀察到變化。它是一個Windows桌面應用程序。 – 2010-11-15 20:23:11

相關問題