繁体   English   中英

在C#中通过引用使用double

[英]Using a double by reference in C#

假设我有一个监控double值的类。 我不想每次在监视类中调用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只能在方法参数中使用。

在此建议附近是否有不包含装箱/拆箱或在每个watch电话中传递d值的解决方案?

谢谢

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

简短的答案是您不能存储对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); }
}

请注意,编译器必须进行一些特殊的提升,但是我不确定声明为结构类型的局部变量的内容/方式! (也就是说,我对缺少它的开销没有要求。)

但是,我确实喜欢闭包,并且发现它“不那么侵入”,因此:

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甚至不能在嵌套的闭包/代理/ lambda中使用。 它们可能会被从当前调用框架中取消/调用。

由于您正在尝试跟踪变量是否发生更改,因此,与其轮询IMHO的更改,更好的方法是将变量包装在可观察的范围内。 然后,当变量更改时,您可以接收事件。 当然,您必须更改从变量读取和写入的方式。

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);

如果要传递对内在值类型的引用,请制作长度为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.
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM