如何在 C# 中误捕获非 CLS 异常 < 2.0?

问题描述 投票:0回答:1

问题如下。基于通过 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; // Re­throws whatever got caught
}
catch {
 // In all versions of C#, this block catches CLS­-compliant
 // non–CLS­-compliant exceptions
 throw; // Re­throws 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
吗?

c# exception try-catch interop
1个回答
0
投票

感谢@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
© www.soinside.com 2019 - 2024. All rights reserved.