2

double 値を監視するクラスがあるとします。監視クラスで監視メソッドを呼び出すたびにその 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 変数に値を格納しているため、これは機能しません。変数を as として宣言しようとしましたref double vが、ref はメソッド パラメーターでのみ使用できます。

dへのすべての呼び出しでボックス化/ボックス化解除または値を渡すことを含まない、この提案の近くの解決策はありますwatchか?

ありがとうございました

注:これを使用したい具体的な状況は、上記のコードとは関係ありません。これは、私が達成したいことを簡単に示す方法にすぎません。

4

4 に答える 4

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); }
}
于 2012-11-04T19:33:41.380 に答える
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この理由から、ネストされたクロージャー/デリゲート/ラムダ内で使用することさえできません。それらは現在の呼び出しフレームから持ち上げられたり呼び出されたりする可能性があります。

于 2012-11-04T19:42:14.470 に答える
1

固有値型への参照を渡したい場合は、長さ 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.
    }
}
于 2014-12-09T21:08:39.277 に答える
0

変数が変更されたかどうかを追跡しようとしているので、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);
于 2012-11-04T20:20:23.943 に答える