Within a C# instance method, can 'this' ever be null?

前端 未结 6 767
栀梦
栀梦 2020-12-17 08:30

I have a situation where very rarely a Queue of Objects is dequeuing a null. The only call to Enqueue is within the class itself:

m_DeltaQueue.Enqueue(this);         


        
相关标签:
6条回答
  • 2020-12-17 08:41

    Queues are not inherently thread safe. This is your issue. Use a mutex/lock/whatever or look for a thread safe-queue.

    0 讨论(0)
  • 2020-12-17 08:46

    It is possible to create a delegate that calls an instance method on a null instance using the Delegate.CreateDelegate(Type, object, MethodInfo) overload.

    The MSDN says (emphasis mine)

    If firstArgument is a null reference and method is an instance method, the result depends on the signatures of the delegate type type and of method:

    • If the signature of type explicitly includes the hidden first parameter of method, the delegate is said to represent an open instance method. When the delegate is invoked, the first argument in the argument list is passed to the hidden instance parameter of method.
    • If the signatures of method and type match (that is, all parameter types are compatible), then the delegate is said to be closed over a null reference. Invoking the delegate is like calling an instance method on a null instance, which is not a particularly useful thing to do.
    0 讨论(0)
  • 2020-12-17 08:49

    this can never be null (the CLR will raise an exception if you try to call a method on null). It's almost certainly the case that you have a synchronization bug, where two threads are trying to add to the queue simultaneously. Perhaps both threads are incrementing an index into the array and then putting their value into the same location. This means that the first thread is getting its value overwritten.

    Either synchronize your access (e.g. with lock) or use a ConcurrentQueue (in .Net 4).

    0 讨论(0)
  • 2020-12-17 08:51

    this can never be null, unless the method was called using a call instruction in hand-written IL.

    However, if you use the same Queue instance on multiple threads simultaneously, the queue will become corrupted and lose data.

    For example, if two items are added simultaneously to a near-capacity queue, the first item might be added to the array after the second thread resizes it, which will end up copying a null to the resized array and adding the first item to the old array.

    You should protect your queues with locks or use .Net 4's ConcurrentQueue<T>.

    0 讨论(0)
  • 2020-12-17 09:04

    Indeed, if the Queue class you are using is not thread safe, you could be Dequeueing from two threads at the same time. The easiest way to avoid this is by locking your queue when you are dequeueing from it.

    
    //declare this object in a globally accessible location
    object locker = new object();
    
    lock(locker)
    {
        m = mDeltaQueue.Dequeue();
    }
    
    0 讨论(0)
  • 2020-12-17 09:06

    (Slightly off-topic and a highly unlikely possibility; have made this community wiki. The real question has already been resolved; this is mainly related to the title of the question.)

    In theory, if your code m_DeltaQueue.Enqueue(this) resulted in the invocation of an implicit conversion operator on the argument, that could indeed result in a null-reference being passed to the method.

    class Foo
    {
        public static implicit operator string(Foo foo)
        {
            return null;
        }
    
        void InstanceMethod()
        {
            string @this = this;
    
            if (@this == null)
                Console.WriteLine("Appears like 'this' is null.");
        }
    
        static void Main()
        {
            new Foo().InstanceMethod();
        }
    }
    
    0 讨论(0)
提交回复
热议问题