C# 4.0 调用-异常处理

C# 4.0 调用-异常处理,c#-4.0,task-parallel-library,C# 4.0,Task Parallel Library,My code运行4函数向类填充信息(使用Invoke),例如: class Person { int Age; string name; long ID; bool isVegeterian public static Person GetPerson(int LocalID) { Person person; Parallel.Invoke(() => {GetAgeFromWebServiceX(per

My code运行4函数向类填充信息(使用Invoke),例如:

class Person
{
    int Age;
    string name;
    long ID;
    bool isVegeterian

    public static Person GetPerson(int LocalID)
    {
        Person person;
        Parallel.Invoke(() => {GetAgeFromWebServiceX(person)}, 
                        () => {GetNameFromWebServiceY(person)},
                        () => {GetIDFromWebServiceZ(person)},
                        () => 
                        {
                           // connect to my database and get information if vegeterian (using LocalID)
                           ....
                           if (!person.isVegetrian)
                               return null
                           ....
                        });
     }
}

我的问题是:如果他不是素食主义者,我不能返回null,但我希望能够停止所有线程,停止处理,只返回null。如何实现它?

好吧,您可以从操作中抛出异常,在
GetPerson
中捕获
aggregateeexception
(即在
Parallel.Invoke
周围放置一个try/catch块),检查它是否是正确的异常类型,然后返回null

除了停止所有线程之外,它完成了所有任务。我认为,除非您开始使用取消令牌,否则您不太可能轻松停止已经在运行的任务。您可以通过保留一个
布尔值来停止执行更多任务,以指示到目前为止是否有任何任务失败,并让每个任务在开始之前检查。。。这有点难看,但会管用的


我怀疑使用“完整”任务而不是
Parallel.Invoke
会使这一切变得更加优雅。

要尽早退出
Parallel.Invoke
,您必须做三件事:

  • 安排检测是否要在第一个操作之前退出的操作。然后它会被提前安排(可能是第一次,但这并不能保证),所以你会很快知道你是否想退出
  • 当检测到错误并捕获Jon的回答所示的
    aggregateeexception
    时引发异常
  • 使用取消代币。然而,这只有在你有机会检查他们的财产时才有意义
  • 您的代码将如下所示:

    var cts = new CancellationTokenSource();
    try
    {
        Parallel.Invoke(
            new ParallelOptions { CancellationToken = cts.Token },
            () =>
            {
                if (!person.IsVegetarian)
                {
                    cts.Cancel();
                    throw new PersonIsNotVegetarianException();
                }
            },
            () => { GetAgeFromWebServiceX(person, cts.Token) }, 
            () => { GetNameFromWebServiceY(person, cts.Token) },
            () => { GetIDFromWebServiceZ(person, cts.Token) }
        );
    }
    catch (AggregateException e)
    {
        var cause = e.InnerExceptions[0];
        // Check if cause is a PersonIsNotVegetarianException.
    }
    

    然而,正如我所说的,取消代币只有在您能够检查它们的情况下才有意义。因此,在
    GetAgeFromWebServiceX
    中应该有机会检查取消令牌并提前退出,否则,将令牌传递给这些方法是没有意义的。

    您确实需要首先从数据库加载您的
    人员
    ?实际上,您的代码使用空值调用Web服务

    如果你的逻辑真的是顺序的,那么按顺序去做,并且只并行地做有意义的事情