在C#中使用double引用

时间:2012-11-04 19:18:02

标签: c# reference

假设我有一个监控双值的类。每次我在监控类中调用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值?

谢谢

注意:我想要使用它的具体情况与上面的代码无关。这只是一种轻松展示我想要实现的目标的方式。

4 个答案:

答案 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.
    }
}