C# 存储对值类型的引用?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2256048/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Store a reference to a value type?
提问by Alex Turpin
I am writing a "Monitor" object to facilitate debugging of my app. This Monitor object can be accessed at run time from an IronPython interpreter. My question is, is it possible in C# to store a reference to a value type? Say I have the following class:
我正在编写一个“监视器”对象以方便调试我的应用程序。这个 Monitor 对象可以在运行时从 IronPython 解释器访问。我的问题是,是否可以在 C# 中存储对值类型的引用?假设我有以下课程:
class Test
{
public int a;
}
Can I somehow store a "pointer" to "a" in order to be able to check it's value anytime? Is it possible using safe and managed code?
我可以以某种方式存储一个指向“a”的“指针”以便能够随时检查它的值吗?是否可以使用安全和托管代码?
Thanks.
谢谢。
采纳答案by Eric Lippert
You cannot store a reference to a variable in a field or array. The CLR requires that a reference to a variable be in (1) a formal parameter, (2) a local, or (3) the return type of a method. C# supports (1) but not the other two.
您不能在字段或数组中存储对变量的引用。CLR 要求对变量的引用位于 (1) 形式参数、(2) 局部参数或 (3) 方法的返回类型中。C# 支持 (1) 但不支持其他两个。
(ASIDE: It is possiblefor C# to support the other two; in fact I have written a prototype compiler that does implement those features. It's pretty neat. (See http://ericlippert.com/2011/06/23/ref-returns-and-ref-locals/for details.) Of course one has to write an algorithm that verifies that no ref local could possibly be referring to a local that was on a now-destroyed stack frame, which gets a bit tricky, but its doable. Perhaps we will support this in a hypothetical future version of the language. (UPDATE: It was added to C# 7!))
(旁白:C#有可能支持另外两个;事实上,我已经编写了一个原型编译器来实现这些功能。它非常简洁。(参见http://ericlippert.com/2011/06/23/ref- Returns-and-ref-locals/了解详情。)当然,必须编写一种算法来验证没有 ref local 可能指代位于现已销毁的堆栈帧上的本地,这有点棘手,但是它是可行的。也许我们会在该语言的假设未来版本中支持这一点。(更新:它已添加到 C# 7!))
However, you can make a variable have arbitrarily long lifetime, by putting it in a field or array. If what you need is a "reference" in the sense of "I need to store an alias to an arbitrary variable", then, no. But if what you need is a reference in the sense of "I need a magic token that lets me read and write a particular variable", then just use a delegate, or a pair of delegates.
但是,您可以通过将变量放在字段或数组中来使变量具有任意长的生命周期。如果您需要的是“我需要将别名存储到任意变量”意义上的“引用”,那么,不。但是,如果您需要的是“我需要一个可以让我读写特定变量的魔法标记”意义上的引用,那么只需使用一个委托或一对委托。
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;
}
The outer local variable x will stay alive at least until rx is reclaimed.
外部局部变量 x 将至少保持活动状态直到 rx 被回收。
回答by Reed Copsey
No - you can't store a "pointer" to a value type directly in C#.
不 - 您不能直接在 C# 中存储指向值类型的“指针”。
Typically, you'd hold a reference to the Test instance containing "a" - this gives you access to a
(via testInstance.a
).
通常,您会持有对包含“a”的 Test 实例的引用 - 这使您可以访问a
(via testInstance.a
)。
回答by Gorlykio
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; }
}
}
Why put yourself through all that hassle of writing complicated code, declaring identifiers everywhere linking to the same location? Make a property, add some XML code to help you outside the class, and use the properties in your coding.
为什么要让自己经历编写复杂代码的所有麻烦,在任何地方都声明链接到同一位置的标识符?创建一个属性,在类之外添加一些 XML 代码来帮助您,并在您的编码中使用这些属性。
I don't know about storing a pointer, don't think it's possible, but if you're just wanting to check its value, the safest way to my knowledge is to create a property of the variable. At least that way you can check its property at any time and if the variable is static, you wouldn't even have to create an instance of the class to access the variable.
我不知道如何存储指针,不认为这是可能的,但是如果您只是想检查它的值,据我所知,最安全的方法是创建变量的属性。至少这样你可以随时检查它的属性,如果变量是静态的,你甚至不必创建类的实例来访问变量。
Properties have a lot of advantages; type safety is one, XML tags another. Start using them!
属性有很多优点;类型安全是一个,XML 标记是另一个。开始使用它们!
回答by Spencer Rose
Here is a pattern I came up with that I find myself using quite a bit. Usually in the case of passing properties as parameters for use on any object of the parent type, but it works just as well for a single instance. (doesn't work for local scope value types tho)
这是我想出的一个模式,我发现自己使用了很多。通常在将属性作为参数传递以用于父类型的任何对象的情况下,但它也适用于单个实例。(不适用于本地范围值类型)
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);
}
}
}
This can then be used like so
然后可以像这样使用
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;
}
Notice the interface with a more limited set of template arguments, this allows you to pass the pointer to something that has no knowledge of the parent type.
注意带有一组更有限的模板参数的接口,这允许您将指针传递给不知道父类型的东西。
You could even implement another interface with no template arguments that calls .ToString on any value type (don't forget the null check first)
你甚至可以实现另一个没有模板参数的接口,在任何值类型上调用 .ToString (不要忘记先检查空值)
回答by ja72
You can literally take a pointer to a value type using usafe
code
您可以使用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
}
}