Vâng, tôi không biết nếu điều này là một lỗi hay chỉ là một thực sự trường hợp cạnh lạ trong đó CERs không được thiết kế để xử lý.
Vì vậy, đây là mã thích hợp.
private static IEnumerable<int> Iterate()
{
RuntimeHelpers.PrepareConstrainedRegions();
try { cerWorked = false; yield return 5; }
finally { StackOverflow(); }
}
Khi điều này được biên soạn và chúng tôi cố gắng dịch ngược lại thành C# với Trình phản xạ, chúng tôi nhận được điều này.
private static IEnumerable<int> Iterate()
{
RuntimeHelpers.PrepareConstrainedRegions();
cerWorked = false;
yield return 5;
}
Bây giờ, hãy chờ một chút! Reflector có tất cả điều này hơi say lên. Đây là những gì IL thực sự trông giống như.
.method private hidebysig static class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> Iterate() cil managed
{
.maxstack 2
.locals init (
[0] class Sandbox.Program/<Iterate>d__1 d__,
[1] class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> enumerable)
L_0000: ldc.i4.s -2
L_0002: newobj instance void Sandbox.Program/<Iterate>d__1::.ctor(int32)
L_0007: stloc.0
L_0008: ldloc.0
L_0009: stloc.1
L_000a: br.s L_000c
L_000c: ldloc.1
L_000d: ret
}
Lưu ý rằng trên thực tế, không gọi tới PrepareConstrainedRegions
bất chấp Reflector nói gì. Vậy nó ở đâu? Vâng, nó ở ngay trong phương pháp MoveNext
được tạo tự động. Lần này Reflector hiểu đúng.
private bool MoveNext()
{
try
{
switch (this.<>1__state)
{
case 0:
this.<>1__state = -1;
RuntimeHelpers.PrepareConstrainedRegions();
this.<>1__state = 1;
Program.cerWorked = false;
this.<>2__current = 5;
this.<>1__state = 2;
return true;
case 2:
this.<>1__state = 1;
this.<>m__Finally2();
break;
}
return false;
}
fault
{
this.System.IDisposable.Dispose();
}
}
Và cuộc gọi đó đến đâu để chuyển sang chế độ StackOverflow
? Ngay bên trong phương thức m_Finally2()
.
private void <>m__Finally2()
{
this.<>1__state = -1;
Program.StackOverflow();
}
Vì vậy, cho phép kiểm tra này một chút chặt chẽ hơn. Hiện tại, chúng tôi có số cuộc gọi PrepareConstainedRegions
bên trong khối try
thay vì ở bên ngoài vị trí cần thiết. Và cuộc gọi StackOverflow
của chúng tôi đã di chuyển từ một khối finally
đến khối try
.
Theo số documentationPrepareConstrainedRegions
phải lập tức đứng trước khối try
. Vì vậy, giả định là nó không có hiệu quả nếu được đặt ở bất kỳ nơi nào khác.
Nhưng, ngay cả khi trình biên dịch C# nhận được phần đúng, mọi thứ sẽ vẫn bị vặn lên vì các khối try
không bị ràng buộc. Chỉ có các khối catch
, finally
và fault
. Và đoán xem? Cuộc gọi StackOverflow
đã được di chuyển từ khối finally
tới khối try
!
Đối với những gì nó có giá trị bạn có vẻ là người đầu tiên nhận thấy điều này ... ít nhất là như xa như tôi có thể nói từ googling cho các tài liệu tham khảo khác của nó. –
Tôi đã tìm thấy đoạn mã https://vmccontroller.svn.codeplex.com/svn/VmcController/VmcServices/DetectOpenFiles.cs này trong đó tác giả không ngờ sẽ không nhận được CER mà anh ta nghĩ là anh ta đang nhận được. –
@Brian: Rất tiếc. Tôi nghĩ rằng đó là điều mà hầu hết mọi người không thường xuyên sử dụng, và những người có thể đã biết trực giác, mà thực sự không bao giờ nghĩ về nó. Chỉ là tôi đoán thôi. – Mehrdad