相关疑难解决方法(0)

C#在foreach中重用变量是否有原因?

在C#中使用lambda表达式或匿名方法时,我们必须警惕对修改后的闭包陷阱的访问.例如:

foreach (var s in strings)
{
   query = query.Where(i => i.Prop == s); // access to modified closure
   ...
}
Run Code Online (Sandbox Code Playgroud)

由于修改后的闭包,上面的代码将导致Where查询中的所有子句都基于最终值s.

正如这里所解释的那样,这是因为上面循环中s声明的变量foreach在编译器中被翻译成这样:

string s;
while (enumerator.MoveNext())
{
   s = enumerator.Current;
   ...
}
Run Code Online (Sandbox Code Playgroud)

而不是像这样:

while (enumerator.MoveNext())
{
   string s;
   s = enumerator.Current;
   ...
}
Run Code Online (Sandbox Code Playgroud)

正如这里所指出的,循环外声明变量没有性能优势,在正常情况下,我能想到这样做的唯一原因是你计划在循环范围之外使用变量:

string s;
while (enumerator.MoveNext())
{
   s = enumerator.Current;
   ...
}
var finalString = s;
Run Code Online (Sandbox Code Playgroud)

但是,foreach循环中定义的变量不能在循环外使用: …

c# foreach lambda scope anonymous-methods

1631
推荐指数
4
解决办法
10万
查看次数

不能引用在不同方法中定义的内部类中的非final变量

编辑:我需要更改几个变量的值,因为它们通过计时器运行几次.我需要通过计时器每次迭代不断更新值.我无法将值设置为final,因为这会阻止我更新值,但是我收到了我在下面的初始问题中描述的错误:

我以前写过以下内容:

我收到错误"不能引用在不同方法中定义的内部类中的非final变量".

这种情况发生在双重调用价格和价格调用priceObject上.你知道我为什么会遇到这个问题.我不明白为什么我需要最后的声明.此外,如果你能看到我想要做的是什么,我该怎么做才能解决这个问题.

public static void main(String args[]) {

    int period = 2000;
    int delay = 2000;

    double lastPrice = 0;
    Price priceObject = new Price();
    double price = 0;

    Timer timer = new Timer();

    timer.scheduleAtFixedRate(new TimerTask() {
        public void run() {
            price = priceObject.getNextPrice(lastPrice);
            System.out.println();
            lastPrice = price;
        }
    }, delay, period);
}
Run Code Online (Sandbox Code Playgroud)

java methods final declaration

244
推荐指数
6
解决办法
19万
查看次数

为什么在lambda表达式中使用迭代变量很糟糕

我只是写了一些快速代码并注意到这个编译器错误

在lambda表达式中使用迭代变量可能会产生意外结果.
相反,在循环中创建一个局部变量并为其分配迭代变量的值.

我知道这意味着什么,我可以很容易地解决它,而不是什么大不了的事.
但我想知道为什么在lambda中使用迭代变量是个坏主意?
我以后可能会遇到什么问题?

vb.net iteration lambda warnings

51
推荐指数
2
解决办法
1万
查看次数

在foreach循环中启动任务使用最后一项的值

我正在尝试使用新任务,但发生了一些我不明白的事情.

首先,代码非常简单.我传入一些图像文件的路径列表,并尝试添加一个任务来处理它们中的每一个:

public Boolean AddPictures(IList<string> paths)
{
    Boolean result = (paths.Count > 0);
    List<Task> tasks = new List<Task>(paths.Count);

    foreach (string path in paths)
    {
        var task = Task.Factory.StartNew(() =>
            {
                Boolean taskResult = ProcessPicture(path);
                return taskResult;
            });
        task.ContinueWith(t => result &= t.Result);
        tasks.Add(task);
    }

    Task.WaitAll(tasks.ToArray());

    return result;
}
Run Code Online (Sandbox Code Playgroud)

我发现,如果我让它运行,例如,单元测试中的3个路径列表,则所有三个任务都使用提供列表中的最后一个路径.如果我单步执行(并减慢循环的处理速度),则使用循环中的每个路径.

有人可以解释一下发生了什么,为什么?可能的解决方法?

c# multithreading task-parallel-library

46
推荐指数
2
解决办法
2万
查看次数

C#5.0中捕获的闭包(循环变量)

这在C#5.0中正常工作(按预期方式):

var actions = new List<Action>();
foreach (var i in Enumerable.Range(0, 10))
{
    actions.Add(() => Console.WriteLine(i));
}
foreach (var act in actions) act();
Run Code Online (Sandbox Code Playgroud)

打印0到9.但是这个显示10次10​​次:

var actions = new List<Action>();
for (var i = 0; i < 10; i++)
{
    actions.Add(() => Console.WriteLine(i));
}
foreach (var act in actions) act();
Run Code Online (Sandbox Code Playgroud)

问题:这是我们在5.0之前的C#版本中遇到的问题; 所以我们不得不使用一个循环局部占位符来进行闭包,它现在已经修复了 - 在C#5.0中 - 在"foreach"循环中.但不是"for"循环!

这背后的原因是什么(也没有解决for循环问题)?

c# foreach closures for-loop c#-5.0

46
推荐指数
1
解决办法
5219
查看次数

为什么Parallel.ForEach比AsParallel()快得多.ForAll()即使MSDN建议不然?

我一直在做一些调查,看看我们如何创建一个贯穿树的多线程应用程序.

为了找到如何以最佳方式实现这一点,我创建了一个运行在我的C:\ disk中的测试应用程序并打开所有目录.

class Program
{
    static void Main(string[] args)
    {
        //var startDirectory = @"C:\The folder\RecursiveFolder";
        var startDirectory = @"C:\";

        var w = Stopwatch.StartNew();

        ThisIsARecursiveFunction(startDirectory);

        Console.WriteLine("Elapsed seconds: " + w.Elapsed.TotalSeconds);

        Console.ReadKey();
    }

    public static void ThisIsARecursiveFunction(String currentDirectory)
    {
        var lastBit = Path.GetFileName(currentDirectory);
        var depth = currentDirectory.Count(t => t == '\\');
        //Console.WriteLine(depth + ": " + currentDirectory);

        try
        {
            var children = Directory.GetDirectories(currentDirectory);

            //Edit this mode to switch what way of parallelization it should use
            int mode = 3;

            switch (mode) …
Run Code Online (Sandbox Code Playgroud)

c# parallel-processing performance foreach multithreading

32
推荐指数
2
解决办法
1万
查看次数

C#事件处理程序委托中的闭包?

我现在来自功能编程背景,如果我不理解C#中的闭包,请原谅我.

我有以下代码来动态生成获取匿名事件处理程序的按钮:

for (int i = 0; i < 7; i++)
{
    Button newButton = new Button();

    newButton.Text = "Click me!";

    newButton.Click += delegate(Object sender, EventArgs e)
    {
        MessageBox.Show("I am button number " + i);
    };

    this.Controls.Add(newButton);
}
Run Code Online (Sandbox Code Playgroud)

我希望"I am button number " + iifor循环的迭代值关闭文本.但是,当我实际运行程序时,每个Button都会说I am button number 7.我错过了什么?我正在使用VS2005.

编辑:所以我想我的下一个问题是,如何捕捉价值?

c# delegates closures anonymous-methods

21
推荐指数
3
解决办法
6175
查看次数

如何将状态对象传递给延续任务?

我正在使用带有C#的.NET 4.0任务并行库(我第一次使用TPL)

我有一个任务A,我想在完成一系列其他任务(B,C,D等)之前完成任务.因此,我想创建任务B,C,D等作为任务A的延续.但是,我想将"状态"对象传递给任务B,将另一个状态对象传递给任务C等.

我可以通过简单地使用带有状态对象的Task构造函数重载将状态对象传递给任务A,例如http://msdn.microsoft.com/en-us/library/dd783035.aspx描述了这个Task构造函数重载:

Task(Action<Object>, Object, CancellationToken) 
Run Code Online (Sandbox Code Playgroud)

这工作正常,第二个参数是我的"状态"对象.

我想创建一个延续任务,例如任务B:

Task taskB = taskA.ContinueWith(/* args here*/)
Run Code Online (Sandbox Code Playgroud)

但是,我看不到ContinueWith()重载(请参阅http://msdn.microsoft.com/en-us/library/dd235663.aspx),它允许我将"状态"对象传递给延续任务.如何才能做到这一点?

笔记:

  1. 在创建taskA时,我没有taskB的'state'对象
  2. taskB的'state'对象不是taskA的输出(返回值)

对于某些上下文,我正在做的是在几个循环中创建taskB,taskC等,所以我使用状态对象将循环变量的值传递给taskB,taskC等,以避免问题总是以任务中的循环变量的最终值结束(闭包问题).

.net c# task-parallel-library

19
推荐指数
1
解决办法
8441
查看次数

因为循环超出范围

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            MyClass myClass = new MyClass();
            myClass.StartTasks();
        }
    }
    class MyClass
    {
        int[] arr;
        public void StartTasks()
        {
            arr = new int[2];
            arr[0] = 100;
            arr[1] = 101;

            for (int i = 0; i < 2; i++)
            {
                Task.Factory.StartNew(() => WorkerMethod(arr[i])); // IndexOutOfRangeException: i==2!!!
            }
        }

        void WorkerMethod(int i)
        {
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

似乎i ++在循环迭代完成之前再次执行.为什么我会得到IndexOutOfRangeException?

c# for-loop

18
推荐指数
2
解决办法
3759
查看次数

在foreach循环中构建的Linq查询始终从最后一次迭代中获取参数值

我有一个包含几个关键字的列表.我预先通过他们像这样构建我的linq查询(煮沸以消除代码噪音):

List<string> keys = FillKeys()
foreach (string key in keys){
    q = q.Where(c => c.Company.Name.Contains(key));
}
Run Code Online (Sandbox Code Playgroud)

当我现在让我的键包含2个键分别返回结果,但不能一起出现(q中的每个项目都是"xyz"或"123",从不"123"和"xyz"),我仍然得到结果.结果集与它到达的最后一个字符串相同.

我查看了linq查询,看起来它创建了正确的sql,但它用相同的(最后一个itterated)值替换了@ p1 AND @ p2.

我究竟做错了什么?

c# linq

17
推荐指数
2
解决办法
1万
查看次数