Referencing Value Variables

I want to do something where I can take any variable, reference type (no problem) or value, and have a reference to the data, rather than just the data (in the case of value variables).


Example:



            //create three objects for reference
            object obj1, obj2, obj3;
            //create two value variables and one reference variable
            int i;
            string s;
            int[] ir = new int[3];

            int[] tir; //used for indexing the object

            //set the values of the data
            i = 10;
            s = "str";
            ir[0] = 3;
            ir[1] = 5;
            ir[2] = 7;

            //assign the objects to their respective variables
            obj1 = i;
            obj2 = s;
            obj3 = ir;
            tir = (int[])obj3; //it's passed through the boject
                               //so the reference carried to start->object

            //change the values of the variables (not the objects)
            i = 5;
            s = "new string";
            ir[0] = 1;
            ir[1] = 2;
            ir[2] = 3;

            //write the simpler types - notice the objects aren't changed
            System.Console.Write("1 (int): {0} = {1}\n 2 (string): \"{2}\"=\"{3}\"\n",
                                  i, obj1, s, obj2);

            //write the complex type, notice the object is changed
            System.Console.Write("3a (arr): ({0}, {1}, {2})\n", ir[0], ir[1], ir[2]);
            System.Console.Write("3b (arr): ({0}, {1}, {2})\n", tir[0], tir[1], tir[2]);

 



in this case, the reference worked fine for the object-type-variable (ir => obj3 => tir), however not from the basic types to obj1 or obj2. Is there any way to get the basic types to work as well (Note this needs to be able to point at any data type for what I need it to do, with only one "pointer" variable).



How I would accomplish this in C (just for a further example):


void *data_ptr; /*point to the data of interest*/
int size_of_data_ptr; /*how many bytes is that data*/

/*now assign it*/
data_ptr = &some_var;
size_of_data_ptr = sizeof(type_of_some_var); /*where type_of_some_var is the type it was declared with.*/

 




Answer this question

Referencing Value Variables

  • Erik Sargent

    Thanks, I did a search and couldn't find any type of watcher before, I wanted to do this just because it seemed like the reference thing could be useful in other situations, however if there is already something that does what I want it to, that'd be great. Thanks.


  • Thomas_

    Thank you, I should have said it before, but a pointer wont work as it's not long term (from everything I've read.)


    What I'm doing is trying to create a variable watcher, that checks a variable list (contains a reference to the original variable, the value of that variable the last time it took a peek, and a callback function to call if those are different). Variables need to be of any type that can be copied by value (through either "=" or a "clone" function - (ICopyable if I remember right)).

    If what I read is correct, the data moves around when not inside the "unsafe" code section, and since there would be a class holding an array of these value triplets, I'm not sure that the references would stick (pretty sure they wouldn't).


    edit: spelling/grammar
    edit: would making a variant variable type that included the basics for the value types (referenced) and object work


  • Galactic Jello

    What you've encountered is known as boxing/unboxing. It allows value types and reference types to both derive from System.Object.

    int i = 42;   // <== allocated on the stack
    object obj = i;   // boxes the value by allocating an object on the heap and copying the value of i into the heap object
    int j = (int)obj; // unboxes the value by copying the value in the heap object back onto the stack

    What you want is a real pointer to a chunk of memory. To do that, you need to write unsafe code. I would recommend trying to re-think your problem to determine if it can be solved in the context of boxing/unboxing instead of writing unsafe code. An assembly that contains unsafe code requires full trust to run, which limits the scenarios in which you can use it. You can also do nasty things like leaking memory, overwriting array bounds, and other crazy stuff that the runtime can no longer protect you from since you're basically saying, "Trust me, I know what I'm doing."

    int i = 42;
    unsafe {
      int* ptr = &i;
      *ptr = 24;
    }
    Console.WriteLine(i);

    Your output will show the value 24.



  • PGT

    Well, I just found out strings are reference variables, and my demo above doesn't work right for strings as I'm re-referencing them.

    And this is mostly for strings (the .Text property of many interface elements), however I don't want it limited to that.

    I like your object->referencestring idea, how do I achieve that

    i.e.


    /*very simplified function*/
    void watch(object myobject, string str, [callback type] callback)
    {
      this.refholder = myobject;
      this.access_str = str;
      this.callback = callback;

      this.last_value = this.refholder/* how do I access the member with the "str" name */;
    }

    /*assign somewhere*/
    watch(some_obj, some_str, oh_no_it_changed);

    /*later it runs the check - this will be called by a thread:*/
    void run_check()
    {
      if(this.last_value != this.refholder/* again, how do I access this.refholder.[str] */
      {
         this.callback()
      }
      wait(this.sleeptime); /*or sleep, forgot the function name, no biggy and easy to fix*/
    }

     



    Thanks again.



  • Nate Walker

    If you're doing this in Windows Forms, why not use the existing DataBinding framework. The System.Windows.Forms.Binding class does much of what your Watcher class would do. The purpose of the Binding object is to keep a visual element (for instance, a TextBox) synchronized with its data source.

    System.Windows.Forms.Binding
    http://msdn2.microsoft.com/library/0sawzdk3(en-us,vs.80).aspx

    If you want some general information on data binding, check out the WinForms FAQ as it provides useful pointers to some good info on data binding:
    http://msdn.microsoft.com/smartclient/community/wffaq/data.aspx#5x02p2uh

    To do it yourself, you would need to use the System.Reflection namespace. This is a fairly advanced topic. Here's a recent article on it by Joel Pobar:
    http://msdn.microsoft.com/msdnmag/issues/05/07/Reflection/default.aspx

  • Ted A. B

    You are correct. The GC is free to rearrange memory and invalidate traditional pointers outside of unsafe or pinned sections. The GC has no control over what you as the programmer do with a traditional pointer and therefore cannot track them across GC compacts of the managed heap.

    You are correct that this technique for watching value types will not work in the face of boxing and GC semantics. You could wrap the basic types as you suggest in a variant-type variable or individually wrap each type separately. (WrappedInt, WrappedFloat, etc.) I wouldn't recommend this approach either as you will have to deal with the cost of boxing/unboxing every time you need the value. This would kill your perf if used in a tight loop, which is typical for value types. (This is why the CLR implements boxing/unboxing as opposed to keeping value types on the managed heap along with reference types.)

    As you can imagine, writing a reference-type watcher is relatively straightforward. Writing a "real" value-type watcher is extremely difficult, if not impossible. (If possible, you would have to write it in C++ with Managed Extensions, listen for GC events, and update pointers when this occurs, which might not even be possible.) Can you instead turn the value-type watching problem into a reference-type watching problem What I mean is monitor the reference type that contains the value type:

    person.Age = 42;
    ValueWatcher watcher = new ValueWatcher();
    watcher.Callback += new ValueWatcherHandler(someMethod);
    watcher.Watch(person, "Age");
    person.Age = 24;

    Now you're monitoring a reference which the GC will move around properly for you. You then use reflection to find the Age property (or field).

    N.B. By watching a reference type, you're holding onto a reference and therefore not allowing it to go out of scope even if the only reference to it is the watcher. If this is the desired behaviour, then you're OK. Otherwise you'll want to look into taking a WeakReference on the watched object in the Watch method.

    Minor correction: The interface you were looking for IClonable, not ICopyable.



  • Referencing Value Variables