从List <t>检索的对象看起来是副本,而不是参考</t>

时间:2010-11-15 20:04:52

标签: c# .net generics

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

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

在代码中,我在解析XML文档时将Badge个实例添加到此列表中。稍后,我想更新列表中的各个实例,以便将数据写回XML。由于数据的XML结构与原始文件结构的不同,所以涉及到一些hocus-pocus,但这很大程度上是映射出来的。当我尝试更新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,我都试过它,只是为了消除它作为罪魁祸首。改变实施没有明显的效果。

对于记录,此应用程序中的所有对象都是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 + "\"";
    }
}

3 个答案:

答案 0 :(得分:1)

或者:

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

答案 1 :(得分:1)

在我看来,这与MenuOption Equals(object)的实施有关。在决定要返回的内容时,IndexOf()的{​​{1}}方法将使用List<>

答案 2 :(得分:0)

通用列表&lt; T&gt;不复制对象。你添加对它的引用,并出现相同的引用 - 所以代码中必定存在另一个问题。

如何实施GetBadgeFromText?它是直接从Badges列表中读取的吗?

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