代码之家  ›  专栏  ›  技术社区  ›  Mike Hofer

从列表中检索的对象似乎是副本,而不是引用

  •  0
  • Mike Hofer  · 技术社区  · 15 年前

    在我的代码中,我有一个维护许多列表的类。我们将暂时关注其中的一个,因为它突出了这个问题。

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

    在代码中,我添加 Badge 解析XML文档时此列表的实例。稍后,我想更新列表中的各个实例,以便将数据写回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类。

    internal Badge GetBadgeByText(string badgeText)
    {
        foreach (var badge in Badges)
        {
            if (badge.Text.ToLower() == badgeText.ToLower())
            {
                return badge;
            }
        }
    
        return null;
        // var b = (from l in Badges
        //         where l.Text.ToLower().StartsWith(badgeText.ToLower())
        //         select l).FirstOrDefault();
        //return b;
    }
    

    正如你所看到的,我尝试过有或没有Linq,只是为了消除这个罪魁祸首。更改实现没有明显的效果。

    另外,这个应用程序中的所有对象都是类。任何地方都没有结构。

    更新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 + "\"";
        }
    }
    
    3 回复  |  直到 15 年前
        1
  •  1
  •   Bryan    15 年前

    在我看来这和 MenuOption 的实现 Equals(object) . 这个 IndexOf() 方法 List<> 将使用 等于(对象) 当决定返回什么时。

        2
  •  1
  •   cdhowie    15 年前

    或者:

    1. 您正在将对象的副本放入列表中。( List<T> 不会克隆对象或进行任何其他欺骗。)
    2. Badge 是一个结构,而不是一个类,这意味着您实际上不持有对它的引用,因为它将是一个值类型。
    3. 在你没有粘贴的代码中有一些复制正在进行。
        3
  •  0
  •   driis    15 年前

    常规列表不复制对象。您添加了对它的引用,同样的引用也会出现,所以代码中肯定还有另一个问题。

    如何实现GetBadgeFromText?它是直接从 Badges 名单?

    这是网络应用吗?如果是,您的列表是否存在于请求之间,或者是否在每个请求上反序列化和序列化(这也可能是问题所在)。