0

Currently, I have this code:

class SO
{
    public SO()
    {
        var ptrManager = new PointerManager();
        int i = 1;

        ptrManager.SavePointer(ref i);

        Console.WriteLine(i); // prints 1

        i = 2; //change value to 2 within the current scope
        Console.WriteLine(i); // prints 2

        ptrManager.SetValue(3); // change value to 3 in another (unsafe) scope
        Console.WriteLine(i); // prints 3
    }
}

unsafe class PointerManager
{
    private int* ptr;
    public void SavePointer(ref int i)
    {
        fixed (int* p = &i)
        {
            ptr = p;
        }
    }

    public void SetValue(int i)
    {
        *ptr = i;
    }
}

First, I tell the PointerManager to create a pointer pointing to my int i. This way, later, i'll be able to tell the PointerManager to change the value of i, without having to pass i in again.

This seems to work well so far. However, I've read that if the GC decides to move i around in memory, then my pointer ptr will become invalid, and subsequent calls to SetValue will have unpredictable behaviour.

So, how do I prevent GC from moving i around? Or, alternatively, is there a better way of accomplishing my goal?

I've also been told that simply adding GCHandle.Alloc(i, GCHandleType.Pinned); will work, but that doesn't seem right...

Edit: To be more specific, GCHandle.Alloc would be called at the beginning of the SavePointer method.

2
  • 1
    Maybe you can describe what problem you are trying to solve? Because it doesn't seem overly useful at first glance.
    – nvoigt
    Commented Sep 13, 2013 at 10:55
  • I'm trying to implement transactional objects. You'd register your variables within the "Manager", do some work, and at a later point, if anything goes wrong, you'd just call manager.Rollback, restoring the values of your variables.
    – dcastro
    Commented Sep 13, 2013 at 10:57

2 Answers 2

1

Generally you do not want to prevent the GC from moving around anything - especially in your case (transactional objects), where I would rather consider options like:

  • making objects savable+restorable=serializable
  • doing it with some sort of manager (maybe this fits well to the idea you had with pointers) that you can pass closures!

Second option explained:

class VariableManager
{
    private Action<int> setter;
    public void VariableManager(Action<int> setter)
    {
        this.setter = setter;
    }

    public void SetValue(int i)
    {
        setter(i);
    }
}

Simply create the manager via new VariableManager(i => yourInt = i) and viola - there you have your desired semantics without pointers!

5
  • Great idea, thanks! Also, can you give me a couple of links about "making objects savable+restorable=serializable"? I'll probably go with closures, but I'd still like to investigate as many alternatives as possible.
    – dcastro
    Commented Sep 13, 2013 at 11:21
  • Glad to help, this MSDN page is a neat starting point to learn about serialization: msdn.microsoft.com/en-us/library/vstudio/ms233843.aspx
    – olydis
    Commented Sep 13, 2013 at 11:24
  • Oh, so that's what you meant? I though you meant something else... See, unless the objects sent to the manager know how to restore themselves, then how would the manager restore them?
    – dcastro
    Commented Sep 13, 2013 at 11:31
  • I can save a copy of the object like this: var serialized = Converter.Serialize(obj), but then how would I restore them at a later point (without using a setter)? Or did you mean that I should make the objects serializable AND use setters?
    – dcastro
    Commented Sep 13, 2013 at 11:32
  • absolutely, serialization (although it is also possible to deserialize INTO existing objects) does not seem to fit your needs that well - I guess I would work with "managers" with setters as well...
    – olydis
    Commented Sep 13, 2013 at 11:48
1

You can use the power of Function and Action types to achieve the same without any unsafe code. Try to avoid any unsafe ocde or pointers, if you aren't interfacing with non-managed code, you don't need them:

using System;

namespace ConsoleApplication16
{
  class SO
  {
    public static void Main()
    {
      var manager = new LateSetter<int>();

      int i = 1;

      manager.SaveSetter(newValue => i = newValue);

      Console.WriteLine(i); // prints 1

      i = 2;
      Console.WriteLine(i); // prints 2

      manager.SetValue(3); // change value to 3
      Console.WriteLine(i); // prints 3

      Console.ReadLine();
    }
  }

  class LateSetter<T>
  {
    private Action<T> set;

    public void SaveSetter(Action<T> setter)
    {
      this.set = setter;
    }

    public void SetValue(T i)
    {
      this.set(i);
    }
  }
}
2
  • Why didn't I think of that?! I'm using the same strategy for other things all over the project! Geez.. One more question though, if the manager receives an Expression with the setter... do you think it is possible to derive the getter? Because I'd have to first get the current value of the closured variable, so I can later set the original value.
    – dcastro
    Commented Sep 13, 2013 at 11:15
  • In other words, I'll need both a getter and a setter, and I wouldn't want to force the user to provide both... I should be able to build the expression tree for a getter if I have a setter, right? (or the other way around)
    – dcastro
    Commented Sep 13, 2013 at 11:17

Not the answer you're looking for? Browse other questions tagged or ask your own question.