【发布时间】:2018-01-30 23:16:08
【问题描述】:
我想知道被调用方法的 out/ref 参数的值是多少。
调用方法时没有抛出异常,在参数中接收到值,但是当调用的方法中抛出异常时,我没有获取到值。直接调用不带Reflection的方法,接收到值。
我做错了什么还是 .net 限制?
using System;
using System.Reflection;
class Program
{
static void Main()
{
string[] arguments = new string[] { bool.FalseString, null };
MethodInfo method = typeof(Program).GetMethod("SampleMethod");
try
{
method.Invoke(null, arguments);
Console.WriteLine(arguments[1]); // arguments[1] = "Hello", Prints Hello
arguments = new string[] { bool.TrueString, null };
method.Invoke(null, arguments);
}
catch (Exception)
{
Console.WriteLine(arguments[1]); // arguments[1] = null, Does not print
}
arguments[1] = null;
try
{
SampleMethod(bool.TrueString, out arguments[1]);
}
catch (Exception)
{
Console.WriteLine(arguments[1]); // arguments[1] = "Hello"
}
}
public static void SampleMethod(string throwsException, out string text)
{
text = "Hello";
if (throwsException == bool.TrueString)
throw new Exception("Test Exception");
}
}
搜索了一下之后,我找到了以下解决方案。好用吗?
using System;
using System.Reflection;
using System.Reflection.Emit;
public static class MethodInfoExtension
{
public static object InvokeStrictly(this MethodInfo source, object obj, object[] parameters)
{
ParameterInfo[] paramInfos = source.GetParameters();
if ((parameters == null) || (paramInfos.Length != parameters.Length))
{
throw new ArgumentException();
}
Type[] paramTypes = new[] { typeof(object[]) };
DynamicMethod invokerBuilder = new DynamicMethod(string.Empty, typeof(object), paramTypes);
ILGenerator ilGenerator = invokerBuilder.GetILGenerator();
Label exBlockLabel = ilGenerator.BeginExceptionBlock();
for (int i = 0; i < paramInfos.Length; i++)
{
var paramInfo = paramInfos[i];
bool paramIsByRef = paramInfo.ParameterType.IsByRef;
var paramType = paramIsByRef ? paramInfo.ParameterType.GetElementType() : paramInfo.ParameterType;
ilGenerator.DeclareLocal(paramType);
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldc_I4, i);
ilGenerator.Emit(OpCodes.Ldelem_Ref);
Label label1 = ilGenerator.DefineLabel();
ilGenerator.Emit(OpCodes.Brfalse, label1);
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldc_I4, i);
ilGenerator.Emit(OpCodes.Ldelem_Ref);
ilGenerator.Emit(OpCodes.Unbox_Any, paramType);
ilGenerator.Emit(OpCodes.Stloc_S, (byte)i);
ilGenerator.MarkLabel(label1);
if (paramIsByRef)
{
ilGenerator.Emit(OpCodes.Ldloca_S, (byte)i);
}
else
{
ilGenerator.Emit(OpCodes.Ldloc_S, (byte)i);
}
}
LocalBuilder resultLocal = ilGenerator.DeclareLocal(typeof(object), false);
ilGenerator.Emit(OpCodes.Call, source);
if (source.ReturnType == typeof(void))
{
ilGenerator.Emit(OpCodes.Ldnull);
}
ilGenerator.Emit(OpCodes.Stloc_S, resultLocal);
ilGenerator.Emit(OpCodes.Leave, exBlockLabel);
ilGenerator.BeginFinallyBlock();
for (int i = 0; i < paramInfos.Length; i++)
{
var paramInfo = paramInfos[i];
bool paramIsByRef = paramInfo.ParameterType.IsByRef;
var paramType = paramIsByRef ? paramInfo.ParameterType.GetElementType() : paramInfo.ParameterType;
ilGenerator.Emit(OpCodes.Ldarg_0);
ilGenerator.Emit(OpCodes.Ldc_I4, i);
ilGenerator.Emit(OpCodes.Ldloc_S, (byte)i);
if (paramType.IsValueType)
{
ilGenerator.Emit(OpCodes.Box, paramType);
}
ilGenerator.Emit(OpCodes.Stelem, typeof(object));
}
ilGenerator.EndExceptionBlock();
ilGenerator.Emit(OpCodes.Ldloc_S, resultLocal);
ilGenerator.Emit(OpCodes.Ret);
var invoker = (Func<object[], object>)invokerBuilder.CreateDelegate(typeof(Func<object[], object>));
return invoker(parameters);
}
}
public class Program
{
static void Main()
{
object[] args = new object[1];
try
{
MethodInfo targetMethod = typeof(Program).GetMethod("Method");
targetMethod.InvokeStrictly(null, args);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
Console.WriteLine();
}
Console.WriteLine(args[0]);
Console.ReadLine();
}
public static void Method(out string arg)
{
arg = "Hello";
throw new Exception("Test Exception");
}
}
【问题讨论】:
标签: c# reflection