C# List<string> 赋值问题

3
我对C#还比较陌生,所以可能难以用语言表达清楚。
我正在创建一个媒体应用程序,其中有一个类(称为MediaFile),包含有关媒体文件的信息(名称、大小、播放次数和标签)。它们分别是字符串、双精度、整数和List类型。
我有一个这些对象的列表,因此例如调用MediaFile [2] .Tags将引用“标签”字符串(相关关键字)的列表。
我的问题是,当我要求用户为选定的MediaFile输入标签时,每当我尝试将这些标签保存到特定对象时,标签都会保存到每个对象中。目前分配的代码看起来像这样:
MediaFile[lstLibrary.SelectedIndices[0]].Tags.Add(tempTag);

'tempTag'是一个字符串,我试图将其添加到字符串列表中,但是就像我说的一样 - 即使只选择了一个文件,'tempTag'字符串也会被添加到每个MediaFile的字符串列表中。

有人能否解释一下我做错了什么?

非常感谢。

编辑:感谢您所有的回复。每当我创建一个MediaFile实例时,我都会将new List<string>传递给构造函数。然后稍后当我去更改这个字符串列表时,我发现所有的MediaFiles似乎都具有相同的字符串引用。以下是MediaFile类:

public static List<MediaType> MediaFile = new List<MediaType>();
public class MediaType
    {
        public string Name;
        public string Path;
        public double Size;
        public int Plays;
        public List<string> Tags;

        // Constructor for adding new files
        public MediaType(string path, List<string> tags)
        {
            Path = path;
            Tags = tags;
        }

当我要求用户选择要添加到媒体库的文件后:

MediaFile.Add(new MediaType(Path.GetFullPath(file), new List<string>()));

一开始没有“标签”,但后来(这就是我的问题所在):

if (tempTag != "")
    MediaFile[lstLibrary.SelectedIndices[0]].Tags.Add(tempTag);
}

有什么想法吗?抱歉这篇文章太长了!

你的错误不在这里。与你列出的代码描述的行为或副作用无关于集合的任何内容。你应该在添加标签的那一行上设置断点,然后调试你的应用程序。当断点被触发时,检查调用堆栈可能会帮助你确定错误所在。 - user1228
我会这样做:var file = MediaFile[lstLibrary.SelectedIndices[0]]; 然后使用调试器查看你得到的对象。如果返回正确的 MediaFile,尝试执行 Tags.Add(...) 看看会发生什么。 - Nobody
你能贴出MediaFile类的一些代码吗? - Adam Lear
6个回答

1

这意味着您已将相同的字符串引用添加到所有MediaFiles中。换句话说,您可能已经执行了以下操作:

List<string> tags = new List<string>();

for (int i = 0; i < 100; i++)
{
    MediaFile file = new MediaFile(tags);
    MediaFiles.Add(file);
}

这很容易测试 - 只需检查 MediaFile [0] .Tags == MediaFile [1] .Tags - 我怀疑您会发现它评估为True,这意味着您正在为两个文件使用相同的列表。

相反,您应该为每个MediaFile实例创建一个新的List<string>

如果您可以发布一些代码,那当然会帮助我们更精确地确定问题...


感谢您的回复,Jon。我已经编辑了我的原始帖子,提供了一些额外的信息。 - Zach Whitfield
@Zach:好的,首先你需要停止使用公共字段 :) 但这并不能解释你所看到的行为。如果你能将代码剪裁成一个简短但完整的示例,那会非常有帮助。请参见http://tinyurl.com/so-hints。 - Jon Skeet

1

看起来你已经将所有的MediaFiles[i].Tags都设置为引用同一个列表实例。


0

我怀疑你的对象初始化不正确。你可能(实际上)是这样创建它们的:

List<string> tags = new List<string>();

MediaFile m1 = new MediaFile();
m1.Tags = tags;

MediaFile m2 = new MediaFile();
m2.Tags = tags;

也就是说,每个MediaFile的Tags属性都指向同一个实际的List<string>对象。因此,当你向m1.Tags添加一个字符串时,也会将其添加到m2.Tags中。

相反,你想要做的是:

MediaFile m1 = new MediaFile();
m1.Tags = new List<string>();

MediaFile m2 = new MediaFile();
m2.Tags = new List<string>();

0
你的Tags属性有一个set访问器吗?
或者你的代码看起来像这样(某些部分)?
var tags = new List<string>();
for (int i = 0; i < MediaFile.Count; ++i)
{
    MediaFile[0] = new MediaFile(tags);
}

如果是这样,那么每个 MediaFile 实例都共享同一个内部的 List<string>

实际上,您根本不应该在此属性上拥有 set 访问器,也不应该让 MediaFile 构造函数接受一些外部的 List<string>(除非它要复制它)。相反,在 MediaFile 构造函数中仅将其分配给 new List<string>();这样你将确保每个实例都获得自己的列表:

public MediaFile()
{
    this.Tags = new List<string>();
}

或者:

public MediaFile(IEnumerable<string> tags)
{
    this.Tags = new List<string>(tags);
}

0

在MediaFile中放置东西的位置在哪里?你怎么做到的呢?

我猜你是把同一个MediaFile对象多次插入列表中。因此,当你修改其中一个对象时,你最终会修改所有的对象,因为它们毕竟是相同的对象。


0

听起来你把列表中的所有对象都设置为使用 Tags 列表的同一个实例了


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接