存储对值类型的引用?

时间:2010-02-13 00:53:43

标签: c# reference

我正在编写一个“Monitor”对象,以方便我的应用程序的调试。可以在运行时从IronPython解释器访问此Monitor对象。我的问题是,在C#中是否可以存储对值类型的引用?说我有以下课程:

class Test
{
    public int a;
}

我可以以某种方式存储“指针”到“a”,以便能够随时检查它的值吗?是否可以使用安全和托管代码?

感谢。

5 个答案:

答案 0 :(得分:52)

您无法在字段或数组中存储对变量的引用。 CLR要求对变量的引用在(1)形式参数中,(2)本地,或(3)方法的返回类型。 C#支持(1)但不支持其他两个。

(ASIDE:C#的可能支持其他两个;事实上我已经编写了一个实现这些功能的原型编译器。它非常整洁。(参见http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/了解详细信息。)当然,必须编写一个算法来验证没有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之前。

答案 1 :(得分:9)

否 - 您无法直接在C#中存储值类型的“指针”。

通常情况下,您会持有对包含“a”的测试实例的引用 - 这样您就可以访问a(通过testInstance.a)。

答案 2 :(得分:2)

这是我提出的一种模式,我发现自己使用了很多。通常在将属性作为参数传递以在父类型的任何对象上使用的情况下,但它对于单个实例也同样有效。 (不适用于本地范围值类型)

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(不要忘记先检查空值)

答案 3 :(得分:0)

您可以使用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
    }
}

答案 4 :(得分:-3)

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标签是另一个。开始使用它们了!