Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/299.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何替换列表模型中的可空对象?_C#_.net - Fatal编程技术网

C# 如何替换列表模型中的可空对象?

C# 如何替换列表模型中的可空对象?,c#,.net,C#,.net,源代码中有一个奇怪的bug,它引用了一个随机变为null的新类。坏的部分是分配给列表模型的空对象。所以,我试图用error对象替换null对象,但运气不好 我收到了这个错误消息 System.ArgumentOutOfRangeException:索引超出范围。尝试替换null对象时,必须为非负且小于集合`的大小 那么,你如何解决这个问题 public class Foo { public bool ErrorFlag { get; set; } } //Sample to produ

源代码中有一个奇怪的bug,它引用了一个随机变为null的新类。坏的部分是分配给列表模型的空对象。所以,我试图用error对象替换null对象,但运气不好

我收到了这个错误消息

System.ArgumentOutOfRangeException:索引超出范围。尝试替换null对象时,必须为非负且小于集合`的大小

那么,你如何解决这个问题

public class Foo
{
    public bool ErrorFlag { get; set; }
}

//Sample to produce the bug...
var modelFoos = new List<Foo>();
modelFoos.Add(new Foo() { ErrorFlag = false; } );
modelFoos.Add(new Foo() { ErrorFlag = false; } );
modelFoos.Add(null);  //This happen when strange bug occurred
modelFoos.Add(new Foo() { ErrorFlag = false; } );
modelFoos.Add(new Foo() { ErrorFlag = false; } );

for(var x = 0; x < modelFoos.Count; x++)
{
    if (modelFoos[x] == null)
    {
        var foo = new Foo() { ErrorFlag = true; };
        modelFoos[x] = foo;  //This is where I get exception error
    }
}

有两件事向我表明,这里正在进行多线程处理,另一个线程正在修改这个列表,而您正在对它进行操作

首先是:

随机变为空

如果它看起来是随机的,并且您正在处理的代码没有改变它,那么它可能正在另一个线程中被改变

但这里有一面更大的旗帜:

if (modelFoos[x] == null)
{
    var foo = new Foo() { ErrorFlag = true; };
    modelFoos[x] = foo;  //This is where I get exception error
}
检查null时,索引没有超出范围,但几行后它超出了范围。这意味着列表中的项目数在这两行代码之间发生了变化,而不是由该代码引起的

这两个迹象似乎表明另一个线程上的某些内容正在对同一个集合进行更改

如果您提供更完整的代码示例,可能会有所帮助。看起来您试图将其简化为在此处发布,但可能缺少相关的详细信息。该列表是从其他地方传递到该方法中的,还是实际上是在该方法中创建的?我的猜测是,它正在被传递,因此有其他引用指向其他内容正在修改的同一列表。

使用 forvar x=0;x而不是forvar x=0;如果代码在并行任务中运行,只需使用 这个问题

lock关键字确保一个线程不会进入关键线程 当另一个线程处于临界段时,执行代码段。如果 另一个线程试图输入锁定的代码,它将等待、阻止, 直到对象被释放


在删除无效分号后,您发布的代码可以正常工作。您能提供一个实际再现问题的最小代码示例吗?我认为您对使用modelFoos的并发线程有问题。如果在示例项目中添加代码,您将看到它运行时没有错误。获取此错误的唯一方法是在您访问数组之前有人修改数组。是的,代码很好。错误消息建议您尝试访问数组中没有的元素,例如,如果您使用的是一个在并行任务中运行的大型脚本,那么您在问题中没有说过。这个“并行”部分很重要-您应该在问题中明确提到这一点。在看不到实际代码的情况下,我猜多个线程可以访问该列表,其中一个线程正在删除项目,而另一个线程试图替换它们。您需要防止这种情况——在修改集合时,不要允许其他线程访问该集合。读写锁在这里可能很有用,或者可能有一个特定的线程安全集合适合您的特定用例。刚刚看到您的最后一条消息-它在并行任务中运行。这符合我的猜测。查看这些并行任务中是否有一个正在将引用设置为null或修改该列表。但此null修复脚本是在并行任务完成并返回列表模型后运行的。如果有一个并行任务正在进行,是否还会有另一个并行任务?另外,您是如何执行并行任务的?它们可能是先执行的,但下一部分是在它们完成之前执行的。正如健全性检查-不要将其保留在代码中-在null修复之前调用System.Threading.Thread.Sleep10000,看看问题是否仍然存在。这不是最简单的调试方法,但我可以推荐这种方法,而不必查看其余的代码。有人警告我们不要使用sleep命令,因为它可能会意外地导致问题。另一个发布这个答案的人说他使用了锁定语句。我从来没有听说过锁,所以我试了一下,效果很好。我可以看到并行任务暂停片刻,然后继续。哇!但是谢谢你的回复。我认为在试图修复空对象时出现了错误,但对我来说,parallel与此无关,因为它已经完成并返回了值。这就是为什么我一开始说“代码很好”,但作者不断地更改它:/Yea,我这样做了。另一个家伙把我搞糊涂了,直到我意识到他错了。这对我来说是新的。现在测试5分钟,到目前为止还不错。现在效果很好。我现在可以看到速度差异,它现在暂停片刻,然后继续。美好的这将阻止其他线程访问相同的代码——锁内的任何代码。它不会保护列表或列表中的项目不被其他线程修改。
private Object thisLock = new Object();

lock (thisLock)
{
   foreach(var x = 0; x < modelFoos.Count; x++)
   {
    if (modelFoos[x] == null)
    {
        var foo = new Foo() { ErrorFlag = true; };
        modelFoos[x] = foo;
    }
  }
}