如何从抛出异常的方法中通过out / ref参数获取值?

时间:2022-11-20 20:36:54

this code outputs "out value".

此代码输出“out value”。

class P
{
  public static void Main()
  {
    string arg = null;
    try
    {
      Method(out arg);
    }
    catch
    {
    }
    Console.WriteLine(arg);
  }
  public static void Method(out string arg)
  {
    arg = "out value";
    throw new Exception();
  }
}

but this one doesn't.

但这个没有。

class P
{
  public static void Main()
  {
    object[] args = new object[1];
    MethodInfo mi = typeof(P).GetMethod("Method");
    try
    {
      mi.Invoke(null, args);
    }
    catch
    {
    }
    Console.WriteLine(args[0]);
  }
  public static void Method(out string arg)
  {
    arg = "out value";
    throw new Exception();
  }
}

how can I get both "out value" and an exception when using reflection?

如何在使用反射时获得“out value”和异常?

5 个解决方案

#1


1  

The exception bypassed the code in MethodInfo.Invoke() that copies the [out] value from the stack frame back into the object array. The value on the stack frame that Invoke() created behaves just like it does in your 1st snippet. But that's where the similarities end.

异常绕过MethodInfo.Invoke()中的代码,该代码将堆栈帧中的[out]值复制回对象数组。 Invoke()创建的堆栈帧上的值与第1段中的值相似。但这就是相似之处的结束。

#2


1  

The only way is to overload your method in a manner that accounts for the possibility of an exception and then pass one in "just in case". The following produces what I think you're looking for. The problem as I understand it is that reflection does not perform direct manipulation of the addresses passed in by reference. The addresses are not affected until the method end point is reached without exception. Possibly a memory protection or memory security scheme from MS.

唯一的方法是以考虑异常可能性的方式重载您的方法,然后在“以防万一”中传递一个。以下产生我认为你正在寻找的东西。我理解的问题是反射不会直接操作通过引用传入的地址。在达到方法结束点之前,地址不会受到影响。可能是MS的内存保护或内存安全方案。

class P
    {
        public static void Main()
        {
            object[] args = { "1", new Exception()};
            MethodInfo mi = typeof(P).GetMethod("Method");
            try
            {
                mi.Invoke(null, args);
            }
            catch
            {
            }
            Console.WriteLine(args[0].ToString());
            Console.WriteLine(args[1].ToString());
        }
        public static void Method(ref string arg, ref Exception ex)
        {
            try
            {
                arg = "out value";
                throw new Exception();
            }
            catch (Exception exc)
            {
                ex = exc;
            }
        }
}

#3


0  

I would propose to change the method to return Result object instead of out parameter. Result object can contain exception and also the value of your arg.

我建议更改方法以返回Result对象而不是out参数。 Result对象可以包含异常以及arg的值。

#4


0  

If the issue is, how do you catch that an exception has occured and you're working with a Windows Forms application, have you tried looking at the Thread Exception Event and combining it with the SetUnhandledExceptionMode()?

如果问题是,如何捕获发生异常并且您正在使用Windows窗体应用程序,您是否尝试查看线程异常事件并将其与SetUnhandledExceptionMode()相结合?

Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)        
{            
    HandleException(e.Exception);        
}

#5


-1  

The out parameter is undefined if the method throws an exception. You can see this by not initialising it to null in the first example, then the code won't compile.

如果方法抛出异常,则out参数未定义。您可以通过在第一个示例中将其初始化为null来看到这一点,然后代码将无法编译。

So, it makes sense for the Invoke method not to return the undefined value if the method throws an exception.

因此,如果方法抛出异常,则Invoke方法不返回未定义的值是有意义的。

#1


1  

The exception bypassed the code in MethodInfo.Invoke() that copies the [out] value from the stack frame back into the object array. The value on the stack frame that Invoke() created behaves just like it does in your 1st snippet. But that's where the similarities end.

异常绕过MethodInfo.Invoke()中的代码,该代码将堆栈帧中的[out]值复制回对象数组。 Invoke()创建的堆栈帧上的值与第1段中的值相似。但这就是相似之处的结束。

#2


1  

The only way is to overload your method in a manner that accounts for the possibility of an exception and then pass one in "just in case". The following produces what I think you're looking for. The problem as I understand it is that reflection does not perform direct manipulation of the addresses passed in by reference. The addresses are not affected until the method end point is reached without exception. Possibly a memory protection or memory security scheme from MS.

唯一的方法是以考虑异常可能性的方式重载您的方法,然后在“以防万一”中传递一个。以下产生我认为你正在寻找的东西。我理解的问题是反射不会直接操作通过引用传入的地址。在达到方法结束点之前,地址不会受到影响。可能是MS的内存保护或内存安全方案。

class P
    {
        public static void Main()
        {
            object[] args = { "1", new Exception()};
            MethodInfo mi = typeof(P).GetMethod("Method");
            try
            {
                mi.Invoke(null, args);
            }
            catch
            {
            }
            Console.WriteLine(args[0].ToString());
            Console.WriteLine(args[1].ToString());
        }
        public static void Method(ref string arg, ref Exception ex)
        {
            try
            {
                arg = "out value";
                throw new Exception();
            }
            catch (Exception exc)
            {
                ex = exc;
            }
        }
}

#3


0  

I would propose to change the method to return Result object instead of out parameter. Result object can contain exception and also the value of your arg.

我建议更改方法以返回Result对象而不是out参数。 Result对象可以包含异常以及arg的值。

#4


0  

If the issue is, how do you catch that an exception has occured and you're working with a Windows Forms application, have you tried looking at the Thread Exception Event and combining it with the SetUnhandledExceptionMode()?

如果问题是,如何捕获发生异常并且您正在使用Windows窗体应用程序,您是否尝试查看线程异常事件并将其与SetUnhandledExceptionMode()相结合?

Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException);

static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e)        
{            
    HandleException(e.Exception);        
}

#5


-1  

The out parameter is undefined if the method throws an exception. You can see this by not initialising it to null in the first example, then the code won't compile.

如果方法抛出异常,则out参数未定义。您可以通过在第一个示例中将其初始化为null来看到这一点,然后代码将无法编译。

So, it makes sense for the Invoke method not to return the undefined value if the method throws an exception.

因此,如果方法抛出异常,则Invoke方法不返回未定义的值是有意义的。