假设我有一个监控双值的类。每次我在监控类中调用monitor方法时,我都不想传递该double值。因此,我想在构造函数中传递对double的引用并存储它,因此我可以直接在monitor方法中比较值。
我的尝试是:
class Monitor {
double v;
public Monitor(ref double x) { v = x; }
public watch() { Console.WriteLine("Value is: " + v); }
}
并将其用于:
double d = 10;
Monitor m = new Monitor(ref d);
while (d > 0) {
m.watch();
d--;
}
不幸的是,这不起作用,因为Monitor构造函数中的赋值将值存储在v变量中。我试图将变量声明为ref double v
,但ref只能在方法参数中使用。
此提案附近是否有任何解决方案不包括装箱/取消装箱或在d
的每次通话中传递watch
值?
谢谢
注意:我想要使用它的具体情况与上面的代码无关。这只是一种轻松展示我想要实现的目标的方式。
答案 0 :(得分:4)
简短的回答是你不能存储对double(或任何其他值类型)的引用。引用只能传递给方法(不存储在调用之间)。
答案很长,你可以将它包装在这样的类中并传递类:
class DoubleWrap
{
protected double val;
public DoubleWrap(double _val) { val = _val; }
public double Value { get { return val } set { val = value; } }
}
然后当你使用它时:
class Monitor {
DoubleWrap v;
public Monitor(DoubleWrap x) { v = x; }
public watch() { Console.WriteLine("Value is: " + v.Value); }
}
答案 1 :(得分:1)
请注意,编译器必须执行某些特殊提升,但我不确定声明为结构类型的局部变量是什么/如何! (也就是说,我没有声称缺乏开销。)
然而,我确实喜欢闭包,发现这是“侵扰性较小”,所以:
class Monitor {
Func<double> v;
public Monitor(Func<double> x) { v = x; }
public watch() { Console.WriteLine("Value is: " + v()); }
}
double d = 10;
Monitor m = new Monitor(() => d);
while (d > 0) {
m.watch();
d--;
}
ref/out
参数(它不是常规类型属性)必须始终引用有效变量(让我们忽略属性的VB.NET技巧)和因此,这些属性不能应用于外部(成员)变量:
在编译时可以确保这个“引用有效变量”语义的唯一方法是限制在当前调用框架中使用ref/out
语义 - 读取:在方法体中 - 作为保证存在具有“引用变量”的调用帧。出于这个原因,ref/out
甚至不能在嵌套的闭包/委托/ lambdas中使用;它们可能会从当前的调用框架中被提升/调用。
答案 2 :(得分:0)
由于您正在尝试跟踪变量是否发生变化,因此更好的做法是将其轮询以进行更改IMHO将您的变量包装在一个observable中。然后,您可以在变量发生变化时接收事件。当然,您必须改变从变量读取和写入的方式。
public class ObservableObject<T>
: INotifyPropertyChanging, INotifyPropertyChanged
{
public ObservableObject(T defaultValue = default(T),
IEqualityComparer<T> comparer = null)
{
this.value = defaultValue;
this.comparer = comparer ?? EqualityComparer<T>.Default;
}
private T value;
private IEqualityComparer<T> comparer;
public T Value
{
get { return value; }
set
{
if (!comparer.Equals(this.value, value))
{
OnValueChanging();
this.value = value;
OnValueChanged();
}
}
}
public event PropertyChangingEventHandler PropertyChanging;
protected virtual void OnValueChanging()
{
var propertyChanging = PropertyChanging;
if (propertyChanging != null)
propertyChanging(this, new PropertyChangingEventArgs("Value"));
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnValueChanged()
{
var propertyChanged = PropertyChanged;
if (propertyChanged != null)
propertyChanged(this, new PropertyChangedEventArgs("Value"));
}
}
然后你可以这样做:
var d = new ObservableObject<double>(10);
d.PropertyChanged += (o, e) =>
{
var obs = (ObservableObject<double>)o;
Console.WriteLine("Value changed to: {0}", obs.Value);
};
Console.WriteLine("Value is: {0}", d.Value);
d.Value = 20;
Console.WriteLine("Value is: {0}", d.Value);
答案 3 :(得分:0)
如果要传递对内在值类型的引用,请创建长度为1的数组。 所有数组都是引用类型。
class A {
private double[] sharedDbl;
public A(double[] d) {
sharedDbl = d;
}
}
class Program {
public static void Main() {
// other code
double[] shared = new double[1];
A a1, a2;
shared[0] = 34.55d;
a1 = new A(shared);
a2 = new A(shared);
// Now both a1 and a2 have a reference to the same double value.
}
}