如何为 this/instance=null 动态调用非静态 System.Object::Equals(object)(例如通过反射)?

How to dynamically invoke non-static System.Object::Equals(object) for this/instance=null (e.g. through reflection)?

如何为 this==null 动态调用非静态 System.Object::Equals(object)

我有 C#:

Nullable<Int32> i1 = 33;
Nullable<Int32> i2 = 33;
i1 = null;

var ret = i1.Equals(i2); //note: i1==null

编译后执行无一例外都会得到ret == false。这是期望的行为。

IL 反汇编行 var ret = i1.Equals(i2); :

IL_001b: ldloca.s     i1
IL_001d: ldloc.1      // i2
IL_001e: box          valuetype [System.Runtime]System.Nullable`1<int32>
IL_0023: constrained. valuetype [System.Runtime]System.Nullable`1<int32>
IL_0029: callvirt     instance bool [System.Runtime]System.Object::Equals(object)
IL_002e: stloc.2      // 'ret'

在后台 - 运行时调用 System.Object::Equals(object) (IL_0029) 方法 instance/this == null

如果我通过反射为 this/instance==null 调用 System.Object::Equals(object) 方法,我得到一个异常 System.Reflection.TargetException "Non-static method requires a target."

调用代码:

Nullable<Int32> i1 = 33;
Nullable<Int32> i2 = 33;
i1 = null;

var equalsMethod = typeof(object).GetMethod("Equals", 
      System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);

var ret2= equalsMethod.Invoke(i1, new object[] { i2 }); //note: i1==null, throw exception 'Non-static method requires a target.'

如果在上面的代码中 i1 设置为某个数字,例如i1 = 3。代码将正确执行。

i1 = 3;
var equalsMethod = typeof(object)
    .GetMethod("Equals", 
    System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
var ret2= equalsMethod.Invoke(i1, new object[] { i2 }); //ret2 will be false

我需要动态调用这个方法。 我无法将其更改为静态方法 '{Boolean Equals (System.Object, System.Object)}'。我在动态调用不同方法的大型项目中需要它。我以 Equals 为例。

反编译方法后System.Reflection.RuntimeMethodInfo.Invoke。它似乎检查 this / instance == null 并抛出异常。 有什么方法可以绕过这个或其他方法吗?

您可以使用表达式树来编译并调用此代码:

   Nullable<Int32> i1 = null;
   Nullable<Int32> i2 = 33;
   var equalsMethod = typeof(object)
        .GetMethod("Equals",
        System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
    var call = Expression.Call(
            Expression.Constant(i1, typeof(int?)),
            equalsMethod,
            Expression.Convert(Expression.Constant(i2), typeof(object)));
    var lambda = Expression.Lambda<Func<bool>>(call).Compile();
    Console.WriteLine(lambda()); // prints false