提问人:Dariusz Woźniak 提问时间:11/4/2023 最后编辑:Dariusz Woźniak 更新时间:11/4/2023 访问量:47
如何在 C# < 2.0 中误捕获非 CLS 异常?
How can I miscatch non-CLS exception in C# < 2.0?
问:
问题如下。基于 CLR via C#(第 4 版):
CLR 的所有编程语言都必须支持引发异常派生对象,因为公共语言规范 (CLS) 强制要求这样做。但是,CLR 实际上允许引发任何类型的实例,并且某些编程语言将允许代码引发不符合 CLS 的异常对象,例如 String、Int32 或 DateTime。 C# 编译器只允许代码引发 Exception 派生对象,而用其他语言编写的代码允许代码抛出 Exception 派生对象以及不是派生自 Exception 的对象。 [...] 尽管 C# 编译器仅允许开发人员抛出异常派生对象,但在 C# 2.0 之前,C# 编译器确实允许开发人员使用此类代码捕获不符合 CLS 的异常。
private void SomeMethod() { try { // Put code requiring graceful recovery and/or cleanup operations here... } catch (Exception e) { // Before C# 2.0, this block catches CLS-compliant exceptions only // Now, this block catches CLS-compliant & non–CLS-compliant exceptions throw; // Rethrows whatever got caught } catch { // In all versions of C#, this block catches CLS-compliant // non–CLS-compliant exceptions throw; // Rethrows whatever got caught } }
你有没有任何工作的例子,可以误捕并直接进入?catch(Exception)
catch
这很有趣。我还没有看到这种行为的任何工作示例,所以我试图重现它。我在 VirtualBox 上安装了 Win XP,然后安装了 .NET Framework 1.1.x、Visual Studio 2003(哇,真是一段怀旧的旅程:)!还安装了 Winamp,Heroes of the...好的,回到问题。
我创建了 C++ 类,编译为 DLL。.cpp 文件为:
#include <exception>
class MyClass {
public:
int doSomething() {
throw 42;
return 1;
}
};
extern "C" __declspec(dllexport) int DoSomethingWrapper() {
MyClass myObject;
return myObject.doSomething();
}
我用 g++ (i686-4.9.3-release-win32-sjlj-rt_v4-rev1) 编译它:
"z:\mingw32\bin\g++.exe" -shared -o "z:\tc.dll" "z:\tc.cpp" -static-libstdc++ -static -static-libgcc
现在,我想在 C# 下运行它并误捕获异常:
class Class1
{
[DllImport("tc.dll")]
public static extern int DoSomethingWrapper();
[STAThread]
static void Main(string[] args)
{
Console.WriteLine("C# version: " + typeof(string).Assembly.ImageRuntimeVersion);
try
{
int i = DoSomethingWrapper();
Console.WriteLine(i);
}
catch(Exception)
{
Console.WriteLine("e");
}
catch
{
Console.WriteLine("empty catch");
}
Console.WriteLine("Final");
Console.Read();
}
}
现在,输出为:
C# version: v1.1.4322
terminate called after throwing an instance of 'int'
另外,将显示消息框:
当我隐含将 DllImport CallingConvention 设置为时,我会得到不同的结果:CallingConvention.FastCall
尽管我在 C# < 2.0 版本中抛出非 CLS 错误,但我不会误会。catch(Exception)
注意 当我删除该行时,代码显示“1”,因此它与 DLL 互操作并获得正确的结果。throw 42
注 2 版本表示 CLR 版本,而不是消息中指示的 C# 版本。但是,我假设 C# 版本是 1.1 或 1.2(基于维基百科文章)。
你知道在这种情况下如何误捕吗?catch(Exception
答:
多亏了@shingo,链接中的示例正在工作。
.il 文件:
.assembly ThrowNonClsCompliantException {}
.class public auto ansi beforefieldinit ThrowsExceptions
{
.method public hidebysig static void
ThrowNonClsException() cil managed
{
.maxstack 1
IL_0000: newobj instance void [mscorlib]System.Object::.ctor()
IL_0005: throw
}
}
.cs 文件:
// CatchNonClsCompliantException.cs
using System;
namespace SecurityLibrary
{
class HandlesExceptions
{
void CatchAllExceptions()
{
try
{
ThrowsExceptions.ThrowNonClsException();
}
catch(Exception e)
{
// Remove some permission.
Console.WriteLine("CLS compliant exception caught");
}
catch
{
// Remove the same permission as above.
Console.WriteLine("Non-CLS compliant exception caught.");
}
}
static void Main()
{
HandlesExceptions handleExceptions = new HandlesExceptions();
handleExceptions.CatchAllExceptions();
}
}
}
IL 汇编程序和 C# 编译器命令:
ilasm /dll ThrowNonClsCompliantException.il
csc /r:ThrowNonClsCompliantException.dll CatchNonClsCompliantException.cs
和。。。在 .NET Framework 1.x 上错过了(预期行为):catch(Exception)
CLR version: v1.1.4322
Non-CLS compliant exception caught
在 Windows 11 和 CLR 4.x 上受到打击(预期行为):catch(Exception)
CLR version: v4.0.30319
CLS compliant exception caught
评论