C# Cannot use ref or out parameter inside an anonymous method body

后端 未结 3 1827
庸人自扰
庸人自扰 2020-12-09 07:40

I\'m trying to create a function that can create an Action that increments whatever integer is passed in. However my first attempt is giving me an error \"cannot use ref or

3条回答
  •  情深已故
    2020-12-09 07:55

    Okay, I've found that it actually is possible with pointers if in unsafe context:

    public static class IntEx {
        unsafe public static Action CreateIncrementer(int* reference) {
            return () => {
                *reference += 1;
            };
        }
    }
    

    However, the garbage collector can wreak havoc with this by moving your reference during garbage collection, as the following indicates:

    class Program {
        static void Main() {
            new Program().Run();
            Console.ReadLine();
        }
    
        int _i = 0;
        public unsafe void Run() {
            Action incr;
            fixed (int* p_i = &_i) {
                incr = IntEx.CreateIncrementer(p_i);
            }
            incr();
            Console.WriteLine(_i); // Yay, incremented to 1!
            GC.Collect();
            incr();
            Console.WriteLine(_i); // Uh-oh, still 1!
        }
    }
    

    One can get around this problem by pinning the variable to a specific spot in memory. This can be done by adding the following to the constructor:

        public Program() {
            GCHandle.Alloc(_i, GCHandleType.Pinned);
        }
    

    That keeps the garbage collector from moving the object around, so exactly what we're looking for. However then you've got to add a destructor to release the pin, and it fragments the memory throughout the lifetime of the object. Not really any easier. This would make more sense in C++, where stuff doesn't get moved around, and resource management is par the course, but not so much in C# where all that is supposed to be automatic.

    So looks like the moral of the story is, just wrap that member int in a reference type and be done with it.

    (And yes, that's the way I had it working before asking the question, but was just trying to figure out if there was a way I could get rid of all my Reference member variables and just use regular ints. Oh well.)

提交回复
热议问题