在C#中存储对象的引用

时间:2011-04-17 13:37:54

标签: c# reference pinning


我目前正在使用C#进行VariableWatcher课程 我想做的是,每次将变量更改为特定值时都要引发事件 例如:我有bool a,这是假的。我将它与要引发事件的值true一起传递给VariableWatcher类。
我已经找到了解决这个问题的方法,但我显然误解了一些关于装箱/拆箱的问题。

这是我的代码:

  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);
    }
}

我的问题是:当我更改时,为什么存储在Value [2]中的对象不会改变?

实施例:

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
}

2 个答案:

答案 0 :(得分:1)

多数民众赞成。它永远不会触发。当您装箱有价值的类型时,您实际上会复制值并将其放入内存中。因此,当您更改变量的值时,您不会更改盒装值。首先想到的是 - 使用不安全的上下文来装箱变量地址但不幸的是.NET不支持装箱指针(from MSDN):

  

指针类型不从对象继承,并且指针类型和对象之间不存在转换。此外,装箱和拆箱不支持指针。但是,您可以在不同的指针类型之间以及指针类型和整数类型之间进行转换。

所以唯一可行的方法 - 使用不安全的上下文并将所有变量的地址存储在void*中,如下所示:

        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());
        }

但是正如评论中提到的那样,为什么不实现在属性发生变化时会触发的事件?

答案 1 :(得分:1)

我终于明白了:

我将Value [2]设置为对象的WeakReference,而不是将其设置为对象的副本。
然后我只需要从WeakReference中获取值,并且有我的目标......