问题如下。基于通过 C# 的 CLR(第 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、英雄无敌……好吧,回到问题上来。
我创建了 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
时,我会得到不同的结果:
我不能错过
catch(Exception)
尽管我在 C# 中抛出非 CLS 错误 < 2.0 version.
注意当我删除
throw 42
行时,代码显示“1”,因此它与 DLL 互操作并获得正确的结果。
NOTE 2 版本表示 CLR 版本,而不是消息所示的 C# 版本。但是,我假设 C# 版本是 1.1 或 1.2(基于 Wikipedia 文章)。
在这种情况下你知道如何误抓
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