Search code examples
c#referencepinning

Storing a reference to a object in C#



I'm currently working on a VariableWatcher class in C#.
What I want to do, is to raise a event every time a variable is changed to a specific value.
For example: I have a bool a , which is false. I pass it to the VariableWatcher class thogether with the value on which the event should be raised, true.
I already made an approach to the solution of this problem, but I obviously misunderstood some point about boxing/unboxing.

This is my code:

  public class ValueWatch
  {
    public delegate void ValueTriggeredD(string ID, string valuename, object source);
    public event ValueTriggeredD ValueTriggered;

    Dictionary<string, object[]> LookUp = new Dictionary<string, object[]>(); //Key = ID, Value[0] = PropertyName, Value[1] = ObjTrigger, Value[2] = ObjWatch
    Timer ttt;

    public void Initialize()
    {
        ttt = new Timer(new TimerCallback(CB_T), null, 0, 50);  
    }
    void CB_T(object o)
    {
        if (LookUp.Count > 0)
        {
            foreach (KeyValuePair<string, object[]> kvp in LookUp)
            {
                Type tp = kvp.Value[2].GetType();
                FieldInfo inf = tp.GetField((string)kvp.Value[0]);
                if (inf != null)
                {
                    object curval = inf.GetValue(kvp.Value[2]);
                    if (curval == kvp.Value[1])
                    {
                        if (ValueTriggered != null)
                            ValueTriggered(kvp.Key, (string)kvp.Value[0], kvp.Value[2]);
                    }
                }
            }
        }
    }
    public void StartWatching(string ID, object ListObj, object ValueForTrigger, string PropertyName)
    {
        if (LookUp.ContainsKey(ID))
            System.Diagnostics.Debug.Print("already there");
        else
        {
            LookUp.Add(ID, new object[] { PropertyName, ValueForTrigger, ListObj });
        }
    }
    public void StopWatching(string ID)
    {
        LookUp.Remove(ID);
    }
}

My question is: Why does the object stored in the Value[2] not change when I change it?

Example:

bool b = false;
valueWatch.ValueTriggered += new ValueTriggeredD(this.VT);
valueWatch.StartWatching("ID1", this, true, "b");
...
b = true;
...
void VT(string ID, string VN, object Source)
{
    //Never triggered
}

Solution

  • Thats right. It will never trigger. When you are boxing valuable types you actually makes a copy of value and put it in memory. So when you are changing variable's value you are not changing boxed value. The first thing which come to mind - using unsafe context to boxing variable addresses but unfortunately .NET is not support boxing of pointers (from MSDN):

    Pointer types do not inherit from object and no conversions exist between pointer types and object. Also, boxing and unboxing do not support pointers. However, you can convert between different pointer types and between pointer types and integral types.

    So the only possible way for you - using unsafe context and storing all variables's addresses in void* as below:

            unsafe
            {
                bool test = false;
                bool* adr = &test;
    
                void* testObj = adr;
                test = true;
                Console.WriteLine("native test's value is" + test.ToString());
                Console.WriteLine("unboxed test's value is" + (*((bool*)testObj)).ToString());
            }
    

    But as it mentioned in comments, why not implement event which would trigger when property has changed?