استثناء معالجة (مكتبة متوازى المهام)
الاستثناءات التي يتم unhandled تم طرح مستخدم بالتعليمات البرمجية قيد التشغيل ضمن مهمة تم نشرها إلى مؤشر ترابط ضم، فيما عدا في بعض وحدات السيناريو التي تم وصفها لاحقاً في هذا الموضوع. تم نشرها الاستثناءات عند استخدام واحد الثابت أو مثيل Waitالأساليب، و مؤشر بها بواسطة إحاطة المكالمة في عبارة catch-حاول. إذا كانت مهمة الأصلية المهام التابعة المتصلة، أو إذا تنتظر تشغيل عدة مهام، ثم استثناءات عديدة يمكن أن يكون تم طرح. لنشر الجميع الاستثناءات الخلف إلى مؤشر ترابط استدعاء، البنية التحتية مهمة يلتف عليها في على AggregateExceptionالمثيل. AggregateExceptionقام InnerExceptionsخاصية التي يمكن أن يتم تعداد لفحص الجميع الاستثناءات الأصلية التي كانت تم طرح، ومعالجة (أو عدم معالجة) كل منها على حدة. حتى في حالة واحدة فقط استثناء يتم طرح، هو لا يزال الملتفة في AggregateException.
Dim task1 = Task.Factory.StartNew(Sub()
Throw New MyCustomException("I'm bad, but not too bad!")
End Sub)
Try
task1.Wait()
Catch ae As AggregateException
' Assume we know what's going on with this particular exception.
' Rethrow anything else. AggregateException.Handle provides
' another way to express this. See later example.
For Each ex In ae.InnerExceptions
If TypeOf (ex) Is MyCustomException Then
Console.WriteLine(ex.Message)
Else
Throw
End If
Next
End Try
var task1 = Task.Factory.StartNew(() =>
{
throw new MyCustomException("I'm bad, but not too bad!");
});
try
{
task1.Wait();
}
catch (AggregateException ae)
{
// Assume we know what's going on with this particular exception.
// Rethrow anything else. AggregateException.Handle provides
// another way to express this. See later example.
foreach (var e in ae.InnerExceptions)
{
if (e is MyCustomException)
{
Console.WriteLine(e.Message);
}
else
{
throw;
}
}
}
يمكن تجنب استثناء unhوled بمجرد catching AggregateExceptionو لا الالتزام بأي من الاستثناءات الداخلي. على الرغم من ذلك، نوصي أن لم تقم th هو لأن ذلك هو مماثل ل catching نوع استثناء الأساسي في وحدات السيناريو غير متوازي. إلى جذب استثناء دون اتخاذ الاجراءات محددة إلى استرداد منه يمكنك المغادرة البرنامج الخاص بك في الولاية غير معرفة.
في حالة عدم الانتظار لمهمة نشر استثناء، أو الوصول إلى خاصية استثناء استثناء هو escalated وفقا للنهج استثناء.NET عند مهمة هو-تجميع البيانات المهملة.
عندما يتم السماح باستثناءات إلى الفقاعة للخلف إلى الانضمام إلى مؤشر الترابط، ثم من الممكن أنه قد يستمر مهمة إلى معالجة بعض عناصر بعد يظهر استثناء.
ملاحظة |
---|
عند "فقط رمز مجلد" هو ممكناً، إلى قطع Studio Vهوual في بعض الحالات تشغيل الخط الذي يطرح استثناء و dهوplay رسالة خطأ تقول "لم يتم التعامل معها من قبل مستخدم رمز استثناء." وهذا خطأ هو benign.يمكنك الضغط على F5 لمتابعة ومشاهدة سلوك معالجة الاستثناءات التي يتم هو موضح في الأمثلة التالية.لمنع الانفصال عن الخطأ أول Visual Studio، فقط إلغاء تحديد "فقط الخاصة بي تعليمات برمجية" خانة الاختيار تحت أدوات، خيارات، تصحيح، عام. |
المهام التابعة المتصلة و AggregateExceptions متداخلة
إذا كان لمهمة مهمة تابعة مرفق يطرح استثناء هذا استثناء هو الملتفة في AggregateExceptionقبله هو نشر للمهمة الأصلية، والتي يلتف هذا استثناء في الخاصة به AggregateExceptionقبل نشر أنه مرة أخرى إلى مؤشر ترابط استدعاء. في مثل هذه الحالات، InnerExceptionsخاصية AggregateExceptionالتي هو تم مصادفة في Waitيحتوي الأسلوب على واحد أو أكثر AggregateExceptions، لا استثناءات الأصلية التي تسببت في الخطأ. إلى تتجنب إلى يكرر عبر المتداخلة AggregateExceptions، يمكنك استخدام Flatten()أسلوب إلى بإزالة الجميع المتداخلة AggregateExceptions، حيث InnerExceptionsيحتوي على خاصية الاستثناءات الأصلي. في المثال التالي، تتداخل AggregateExceptionsتسقط والتعامل معها في ألتو واحد تكرار حلقي.
' task1 will throw an AE inside an AE inside an AE
Dim task1 = Task.Factory.StartNew(Sub()
Dim child1 = Task.Factory.StartNew(Sub()
Dim child2 = Task.Factory.StartNew(Sub()
Throw New MyCustomException("Attached child2 faulted.")
End Sub,
TaskCreationOptions.AttachedToParent)
End Sub,
TaskCreationOptions.AttachedToParent)
' Uncomment this line to see the exception rethrown.
' throw new MyCustomException("Attached child1 faulted.")
End Sub)
Try
task1.Wait()
Catch ae As AggregateException
For Each ex In ae.Flatten().InnerExceptions
If TypeOf (ex) Is MyCustomException Then
Console.WriteLine(ex.Message)
Else
Throw
End If
Next
'or like this:
' ae.Flatten().Handle(Function(e)
' Return TypeOf (e) Is MyCustomException
' End Function)
End Try
// task1 will throw an AE inside an AE inside an AE
var task1 = Task.Factory.StartNew(() =>
{
var child1 = Task.Factory.StartNew(() =>
{
var child2 = Task.Factory.StartNew(() =>
{
throw new MyCustomException("Attached child2 faulted.");
},
TaskCreationOptions.AttachedToParent);
// Uncomment this line to see the exception rethrown.
// throw new MyCustomException("Attached child1 faulted.");
},
TaskCreationOptions.AttachedToParent);
});
try
{
task1.Wait();
}
catch (AggregateException ae)
{
foreach (var e in ae.Flatten().InnerExceptions)
{
if (e is MyCustomException)
{
// Recover from the exception. Here we just
// print the message for demonstration purposes.
Console.WriteLine(e.Message);
}
else
{
throw;
}
}
// or ...
// ae.Flatten().Handle((ex) => ex is MyCustomException);
}
استثناءات من مفصول فرع المهام
افتراضياً، يتم تاريخ الإنشاء tكـks الفرعة كـ فصل. يجب أن تكون معالجة الاستثناءات طرح من فصل tكـks أو rethrown في tكـk الأصل الفوري؛ لا يقومون بنشرها مرة أخرى إلى مؤشر ترابط استدعاء بنفس الطريقة كـ مرفقة tكـks التابعة التي تم نشرها مرة أخرى. يمكنك يدوياً إعادة الطرح الأصل الأعلى إستثناء من فصل فرع مما يؤدي إلى أن التفاف في AggregateExceptionونشرها مرة أخرى لضم مؤشر ترابط.
Dim task1 = Task.Factory.StartNew(Sub()
Dim nestedTask1 = Task.Factory.StartNew(Sub()
Throw New MyCustomException("Nested task faulted.")
End Sub)
' Here the exception will be escalated back to joining thread.
' We could use try/catch here to prevent that.
nestedTask1.Wait()
End Sub)
Try
task1.Wait()
Catch ae As AggregateException
For Each ex In ae.Flatten().InnerExceptions
If TypeOf (ex) Is MyCustomException Then
' Recover from the exception. Here we just
' print the message for demonstration purposes.
Console.WriteLine(ex.Message)
End If
Next
End Try
var task1 = Task.Factory.StartNew(() =>
{
var nested1 = Task.Factory.StartNew(() =>
{
throw new MyCustomException("Nested task faulted.");
});
// Here the exception will be escalated back to joining thread.
// We could use try/catch here to prevent that.
nested1.Wait();
});
try
{
task1.Wait();
}
catch (AggregateException ae)
{
foreach (var e in ae.Flatten().InnerExceptions)
{
if (e is MyCustomException)
{
// Recover from the exception. Here we just
// print the message for demonstration purposes.
Console.WriteLine(e.Message);
}
}
}
حتى إذا كنت تستخدم متابعة إلى ملاحظة يجب أن تكون العينتين استثناء في مهمة تابعة، استثناء ما يزال بالمهمة الأصلية.
استثناءات التي تشير إلى إلغاء التعاونية
عندما يستجيب رمز مستخدم في مهمة لطلب إلغاء إجراء الصحيح هو طرح OperationCanceledExceptionتمرير في الرمز المميز للإلغاء الذي تم توصيلها الطلب. قبل أن يحاول ينشر استثناء، مثيل مهمة الذي يقارن بين الرمز المميز في استثناء إلى واحد التي تم تمريرها إليها عند إنشائه. إذا كانت هي نفسها، نشر مهمة TaskCanceledExceptionالملتفة في AggregateException، و فإنه يمكن رؤية متى يتم فحص الاستثناءات الداخلي. ومع ذلك، إذا وصل مؤشر ترابط هو عدم انتظار على مهمة، وترتيب هو سوف لا يمكن نشر استثناء محدد. لمزيد من المعلومات، راجع إلغاء مهمة.
Dim someCondition As Boolean = True
Dim tokenSource = New CancellationTokenSource()
Dim token = tokenSource.Token
Dim task1 = Task.Factory.StartNew(Sub()
Dim ct As CancellationToken = token
While someCondition = True
' Do some work...
Thread.SpinWait(500000)
ct.ThrowIfCancellationRequested()
End While
End Sub,
token)
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
var task1 = Task.Factory.StartNew(() =>
{
CancellationToken ct = token;
while (someCondition)
{
// Do some work...
Thread.SpinWait(50000);
ct.ThrowIfCancellationRequested();
}
},
token);
// No waiting required.
تستخدم في معالجة أسلوب إلى استثناءات داخلي عامل تصفية
يمكنك استخدام Handle()أسلوب إلى بتصفية الاستثناءات التي يمكن التعامل مع الشكل "معالجه" بدون استخدام منطق آخر. في مستخدم المفوض الذي هو تزويدك Handle، يمكنك فحص نوع استثناء، أو به Messageخاصية، أو أية معلومات غير ذلك حول هذا يسمح لك بتحديد ما إذا كان ذلك هو benign. سرد أية استثناءات التي ترجع المفوض falseيتم rethrown في جديد AggregateExceptionمثيل فور Handleإرجاع.
يلي قصاصة يستخدم foreachتكرار حلقي عبر استثناءات الداخلي.
For Each ex In ae.InnerExceptions
If TypeOf (ex) Is MyCustomException Then
Console.WriteLine(ex.Message)
Else
Throw
End If
Next
foreach (var e in ae.InnerExceptions)
{
if (e is MyCustomException)
{
Console.WriteLine(e.Message);
}
else
{
throw;
}
}
يظهر المتكررة التالية الاستخدام المكافئ functionally Handle()أسلوب.
ae.Handle(Function(ex)
Return TypeOf (ex) Is MyCustomException
End Function)
ae.Handle((ex) =>
{
return ex is MyCustomException;
});
الالتزام باستثناءات بواسطة باستخدام خاصية مهمة. استثناء
في الولاية اكتمال مهمة في الولاية خاطئ، وبه Exceptionيمكن أن يكون فحص خاصية إلى اكتشاف أي استثناء محدد بسبب الخطأ. طريقة بضاعة إلى الانتباه Exceptionخاصية إلى استخدام متابعة يعمل فقط إذا كانت مهمة antecedent faults، كما هو موضح في المثال التالي.
Dim task1 = Task.Factory.StartNew(Sub()
Throw New MyCustomException("task1 faulted.")
End Sub).ContinueWith(Sub(t)
Console.WriteLine("I have observed a {0}", _
t.Exception.InnerException.GetType().Name)
End Sub,
TaskContinuationOptions.OnlyOnFaulted)
var task1 = Task.Factory.StartNew(() =>
{
throw new MyCustomException("Task1 faulted.");
})
.ContinueWith((t) =>
{
Console.WriteLine("I have observed a {0}",
t.Exception.InnerException.GetType().Name);
},
TaskContinuationOptions.OnlyOnFaulted);
في تطبيق حقيقي، المفوض متابعة تسجيل معلومات مُفصل حول استثناء وقد ينتج من المحتمل أن يكون للمهام الجديدة إلى الاسترداد من استثناء.
حدث UnobservedTaskException
في بعض وحدات السيناريو، مثل غير الموثوق عندما يستضيف بها المكونات الإضافية، استثناءات benign قد تكون عام، وقد يكون من الصعب إلى أ إلى يدوياً لاحظ جميعا. في هذه الحالات، يمكنك معالجة TaskScheduler.UnobservedTaskExceptionحدث. System.Threading.Tasks.UnobservedTaskExceptionEventArgsحالة فيها هو التي تم تمريرها إلى المعالج الخاص بك يمكن أن تستخدم لمنع استثناء unobserved من التي يتم نشرها إلى مؤشر ترابط ضم.