我正在编写一个“Monitor”对象,以方便我的应用程序的调试。可以在运行时从IronPython解释器访问此Monitor对象。我的问题是,在C#中是否可以存储对值类型的引用?说我有以下课程:
class Test
{
public int a;
}
我可以以某种方式存储“指针”到“a”,以便能够随时检查它的值吗?是否可以使用安全和托管代码?
感谢。
答案 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标签是另一个。开始使用它们了!