簡體   English   中英

存儲對值類型的引用?

[英]Store a reference to a value type?

我正在編寫一個“監視器”對象,以方便我的應用程序的調試。 可以在運行時從IronPython解釋器訪問此Monitor對象。 我的問題是,在C#中是否可以存儲對值類型的引用? 說我有以下課程:

class Test
{
    public int a;
}

我可以以某種方式存儲“指針”到“a”,以便能夠隨時檢查它的價值嗎? 是否可以使用安全和托管代碼?

謝謝。

您不能在字段或數組中存儲對變量的引用。 CLR要求對變量的引用在(1)形式參數中,(2)本地,或(3)方法的返回類型。 C#支持(1)但不支持其他兩個。

(旁白:這是可能的C#支持其他兩個,事實上我寫了一個原型編譯器確實實現這些功能這是相當整潔(見。 http://ericlippert.com/2011/06/23/ref- return-and-ref-locals / for details。)當然,必須編寫一個算法來驗證沒有ref本地可能引用現在被破壞的堆棧幀上的本地,這有點棘手,但是也許我們會在假設的未來版本的語言中支持這一點。(更新:它被添加到C#7!))

但是,通過將變量放在字段或數組中,可以使變量具有任意長的生命周期。 如果您需要的是“我需要將別名存儲到任意變量”的“參考”,那么,不。 但是,如果您需要的是“我需要一個允許我讀寫特定變量的魔術令牌”的參考,那么只需使用一個委托或一對委托。

sealed class Ref<T> 
{
    private Func<T> getter;
    private Action<T> setter;
    public Ref(Func<T> getter, Action<T> setter)
    {
        this.getter = getter;
        this.setter = setter;
    }
    public T Value
    {
        get { return getter(); }
        set { setter(value); }
    }
}
...
Ref<string> M() 
{
    string x = "hello";
    Ref<string> rx = new Ref<string>(()=>x, v=>{x=v;});
    rx.Value = "goodbye";
    Console.WriteLine(x); // goodbye
    return rx;
}

外部局部變量x將保持活着至少直到rx被回收。

否 - 您無法直接在C#中存儲值類型的“指針”。

通常情況下,你抱着含有“A”測試實例的引用-這讓你訪問a (通過testInstance.a )。

這是我提出的一種模式,我發現自己使用了很多。 通常在將屬性作為參數傳遞以在父類型的任何對象上使用的情況下,但它對於單個實例也同樣有效。 (不適用於本地范圍值類型)

public interface IValuePointer<T>
{
    T Value { get; set; }
}
public class ValuePointer<TParent, TType> : IValuePointer<TType>
{
    private readonly TParent _instance;
    private readonly Func<TParent, TType> _propertyExpression;
    private readonly PropertyInfo _propInfo;
    private readonly FieldInfo _fieldInfo;

    public ValuePointer(TParent instance, 
                        Expression<Func<TParent, TType>> propertyExpression)
    {
        _instance = instance;
        _propertyExpression = propertyExpression.Compile();
        _propInfo = ((MemberExpression)(propertyExpression).Body).Member as PropertyInfo;
        _fieldInfo = ((MemberExpression)(propertyExpression).Body).Member as FieldInfo;
    }

    public TType Value
    {
        get { return _propertyExpression.Invoke(_instance); }
        set
        {
            if (_fieldInfo != null)
            {
                _fieldInfo.SetValue(_instance, value);
                return;
            }
            _propInfo.SetValue(_instance, value, null);
        }
    }
}

然后可以像這樣使用它

class Test
{
    public int a;
}
void Main()
{
    Test testInstance = new Test();
    var pointer = new ValuePointer(testInstance,x=> x.a);
    testInstance.a = 5;
    int copyOfValue = pointer.Value;
    pointer.Value = 6;
}

注意具有更有限的模板參數集的接口,這允許您將指針傳遞給不知道父類型的東西。

你甚至可以實現另一個沒有模板參數的接口,它可以在任何值類型上調用.ToString(不要先忘記空檢查)

您可以使用usafe代碼從字面上獲取指向值類型的指針

public class Foo
{
    public int a;
}

unsafe static class Program
{
    static void Main(string[] args)
    {
        var f=new Foo() { a=1 };
        // f.a = 1

        fixed(int* ptr=&f.a)
        {
            *ptr=2;
        }
        // f.a = 2
    }
}
class Test
{
    private int a;

    /// <summary>
    ///  points to my variable type interger,
    ///  where the identifier is named 'a'.
    /// </summary>
    public int A
    {
        get { return a; }
        set { a = value; }
    }
}

為什么要讓自己完成編寫復雜代碼的麻煩,在任何地方聲明鏈接到同一位置的標識符? 創建一個屬性,添加一些XML代碼以幫助您在課外,並使用編碼中的屬性。

我不知道存儲指針,不認為它是可能的,但如果你只是想檢查它的值,我知道的最安全的方法是創建變量的屬性。 至少你可以隨時檢查它的屬性,如果變量是靜態的,你甚至不必創建類的實例來訪問變量。

屬性有很多優點; 類型安全是一個,XML標簽是另一個。 開始使用它們!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM