1

我有一个声明为的类public class DatumSet : List<datum>,其中

public struct datum {
    public UInt32[] chan;
    public UInt64 sample_number;
    public float time;
    public UInt32 source_sector;
}

我想遍历列表并进行一些更改。为什么这不起作用

        for (int i = 0; i < this.Count; i++) {
            this[i].sample_number = startSample;
            this[i].time = (float)startSample / _sample_rate;
            startSample++;
        }

但这确实有效

        for (int i = 0; i < this.Count; i++) {
            datum d = this[i];
            d.sample_number = sampleNumber;
            d.time = (float)sampleNumber / _sample_rate;
            sampleNumber++;
        }

我得到错误:

无法修改“System.Collections.Generic.List.this[int]”的返回值,因为它不是变量

4

2 回答 2

13

这就是使用可变值类型所得到的:)

将索引器想象成一个方法调用。所以这:

this[i].sample_number = startSample;

就好像:

GetValue(i).sample_number = startSample;

但是因为datum是值类型(结构),所以该方法返回列表中值的副本——所以修改它对你没有任何好处。

编译器正在阻止你犯这个错误。

声称这有效:

for (int i = 0; i < this.Count; i++) {
    datum d = this[i];
    d.sample_number = sampleNumber;
    d.time = (float)sampleNumber / _sample_rate;
    sampleNumber++;
}

...但实际上,它没有任何用处。它相当于:

sampleNumber += this.Count;

就这样。它可以编译,但这与它的工作方式不同。

我建议您将所有值类型设为不可变;它有助于防止您陷入这种混乱。因此您可以保留datum为值类型,并在每次迭代时替换列表中的值,或者您可以将其更改为类,并通过存储在列表中的引用修改对象。

(无论哪种方式,我强烈建议您开始使用属性而不是公共字段,并开始遵循 .NET 命名约定。)

于 2012-11-20T22:33:07.580 回答
9

您遇到问题是因为您使用的是结构而不是类。

当您从集合中检索结构时,会生成一个副本。你的第一组代码给你一个错误,因为它检测到你正在做一些你可能不想做的事情。您实际上是在编辑结构的副本,而不是集合中的副本。

第二个不会产生错误,因为您在编辑之前明确地将副本从集合中拉出。此代码可以编译,但不会修改集合中的任何结构,因此不会给您预期的结果。

于 2012-11-20T22:32:37.767 回答