在C#虚拟方法中,"this"可以为null吗?其他实例方法会发生什么?

Mic*_*dis 13 c# il this c#-4.0

我很好奇是否有一种方法this可以在C#中的虚方法中为null.我认为这是不可能的.我在现有代码中看到,在代码审查期间,我希望100%肯定对其删除进行评论,但我想要一些确认和社区的更多上下文.this != null在任何非静态/实例方法中都是这种情况吗?否则它会是一个空指针异常对吗?我正在考虑扩展方法以及我可能不熟悉多年Java的C#特性.

Luk*_*keH 14

它不是标准的C#,但是,除了LasseJon的答案之外,还有一些IL-fiddling你可以进行非虚拟调用(虚拟或非虚拟方法)传递null this:

using System;
using System.Reflection.Emit;

class Test
{
    static void Main()
    {
        CallWithNullThis("Foo");
        CallWithNullThis("Bar");
    }

    static void CallWithNullThis(string methodName)
    {
        var mi = typeof(Test).GetMethod(methodName);

        // make Test the owner type to avoid VerificationException
        var dm = new DynamicMethod("$", typeof(void), Type.EmptyTypes, typeof(Test));
        var il = dm.GetILGenerator();
        il.Emit(OpCodes.Ldnull);
        il.Emit(OpCodes.Call, mi);
        il.Emit(OpCodes.Ret);

        var action = (Action)dm.CreateDelegate(typeof(Action));
        action();
    }

    public void Foo()
    {
        Console.WriteLine(this == null ? "Weird" : "Normal");
    }

    public virtual void Bar()
    {
        Console.WriteLine(this == null ? "Weird" : "Normal");
    }
}
Run Code Online (Sandbox Code Playgroud)


Jon*_*eet 8

无论方法是否为虚拟,都无法在正常的C#中执行此操作(即以正常方式调用方法或属性).

对于非虚方法,您可以从开放实例方法创建委托,有效地将实例方法视为具有目标类型的第一个参数的静态方法.您可以使用null参数调用该委托,并this == null在方法中进行观察.

对于虚拟方法,您必须非虚拟地调用该方法 - 这可能发生在诸如base.Foo(...)...之类的调用中,但我不确定是否有任何方法可以使用null进行那种非虚拟调用论点.委托方法肯定适用于此.

演示代码:

using System;

class Test
{
    static void Main()
    {
        Action<Test> foo = (Action<Test>)
            Delegate.CreateDelegate(typeof(Action<Test>), typeof(Test).GetMethod("Foo"));
        foo(null); // Prints Weird
        Action<Test> bar = (Action<Test>)
            Delegate.CreateDelegate(typeof(Action<Test>), typeof(Test).GetMethod("Bar"));

        bar(null); // Throws
    }

    public void Foo()
    {
        Console.WriteLine(this == null ? "Weird" : "Normal");
    }

    public virtual void Bar()
    {
        Console.WriteLine(this == null ? "Weird" : "Normal");
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 你可以通过使用`DynamicMethod`创建委托来非虚拟地调用`Bar`.有关示例,请参阅[我的回答](http://stackoverflow.com/a/31749049/55847). (3认同)

Guf*_*ffa 7

this虚拟呼叫中无法为空.如果您有一个空引用,那么您没有对象的实例,如果您没有对象的实例,则无法获取对象的类型来确定要调用的虚拟方法.

在非虚方法中this也不能为空,但这是因为编译器不允许你进行调用,理论上可以进行调用.您可以在空引用上调用扩展方法,这将使this参数为null.

类似地,理论上可以使用空引用对虚拟方法进行非虚拟调用.指定确切的方法,并使用反射可能可以绕过编译器中的限制并使用空引用调用该方法.