1

重複の可能性:
C# のクラス フィールドに「参照」で割り当てるにはどうすればよいですか?

自分の値型の参照を別の値型にコピーしたいと考えています。unsafeパラダイムを使わなくても可能ですか?

int a = 10;
int b = 15;
a = b; // BUT I WANT TO SET REFERENCE OF b !

これが私の実際の例です。列挙値型を作成し、参照によってパラメーターとして送信します。

   public enum Test
{
    test1,
    test2,
    test3
}

public class MyTestClass1
{
    private Test _test;

    public MyTestClass1(ref Test test)
    {
        _test = test;
    }
}

public class Content
{
    public void Method()
    {
        Test e = Test.test1;
        /*some code*/
        var omyTestClass1 = new MyTestClass1(ref e);
        /*some code*/
        e = Test.test2;
        /*some code*/
        e = Test.test3;
    }
}
4

4 に答える 4

1

unsafe構造体/クラス内で値型を使用またはラップせずにこれを行うことはできません。

MSDNから:

ある値型変数を別の値型変数に割り当てると、含まれている値がコピーされます。

于 2012-09-04T14:45:06.117 に答える
1

同じメソッド内の別のローカル変数への参照を含むローカル変数を持つことはできません。考えられる同様の状況、メソッドパラメータが呼び出し元のメソッドでローカル変数への参照を持っている場合です。

void CallingMethod()
{
    int a = 10;
    SomeMethod(ref a);
    ...
}

void SomeMethod(ref int b)
{
    // here, the variable b holds a reference to CallingMethod's local variable "a".

bローカル変数以外のものへの参照を保持できることに注意してください。たとえば、次のようにSomeMethodを呼び出すことができます。この場合、参照はヒープ上のオブジェクトのフィールドを指します。

class MyClass
{
    private int _a;
    public void AnotherCaller()
    {
        SomeMethod(ref _a);
        ...
    }
}

更新:CLRがサポートしており、C#がサポートしている可能性があるため、EricLippertがあなたが求めている機能について時々書いています。たとえば、この回答を参照してください:https ://stackoverflow.com/a/4923772/385844

于 2012-09-04T14:47:33.967 に答える
1

あなたの方法が実際にあった場合:

public MyTestClass1 Method()
{
    Test e = Test.test1;
    /*some code*/
    var omyTestClass1 = new MyTestClass1(ref e);
    /*some code*/
    e = Test.test2;
    /*some code*/
    e = Test.test3;
    return omyTestClass1;
}

返された値には、スタック上にあった値型への参照が含まれていますが、現在はありません。そのフィールドにアクセスしようとすると、何でも取得できます。

さらに悪いことに、そのリファレンスに書いたらどうなるでしょうか? その参照がすべての時間をレジスターに費やすのではなく、実際の呼び出しスタックに格納されていた場合 (そして、それを参照するクラスにフィールドがあったという事実自体が、それがあります)、今そこにあるのは何ですか?オブジェクトへの参照である可能性があります。返送先住所になる可能性があります。それに書き込みを行うと、奇妙なファンダンゴ・オン・ザ・コアのバグが発生する可能性があり、おそらく書き込み後しばらくしてからデバッグが困難になる可能性があります。

私たちが持っている基本的な保証の一部を失うことになります。その値を書き込んだ後は、ほぼすべてのコードが奇妙な方法で失敗する可能性があります。

この時点で注目に値するのは、C++ と .NET 自体 (つまり、C# ではできないものを含む .NET でできることすべて) は、ローカル参照を許可し、ref の戻り値を許可しないということです。田畑。

最も近いのは、ラムダおよび匿名メソッドで発生するキャプチャです。ここでは、ローカルはスタックではなくヒープに保存され、ライブによってキャプチャされたラムダが続く限り生き続けることができます (最後のものが収集されたときに収集されます)。これを使用して、オブジェクト内のローカルとして開始されたものへの参照を維持できます。

または、値型をラップするために必要な作業を行うクラスを使用できます。たとえば、同様の必要性があったときに使用したものを次に示します。

public sealed class SharedInt
{
  private int _value;
  /// <summary>Creates a new SharedInt with a value of zero.</summary>
  public SharedInt(){}
  /// <summary>Creates a new SharedInt.</summary>
  /// <param name="value">The initial value of the object.</param>
  public SharedInt(int value)
  {
    _value = value;
  }
  /// <summary>Returns the value of the SharedInt.</summary>
  public int Value
  {
    get { return _value; }
  }
  /// <summary>Returns the value of the SharedInt.</summary>
  /// <param name="ri">The SharedInt to cast.</param>
  /// <returns>An integer of the same value as the SharedInt.</returns>
  public static implicit operator int(SharedInt ri)
  {
    return ri._value;
  }
  /// <summary>Atomically increment the value of the SharedInt by one.</summary>
  /// <returns>The new value.</returns>
  public int Increment()
  {
    return Interlocked.Increment(ref _value);
  }
  /// <summary>Atomically decrement the value of the SharedInt by one.</summary>
  /// <returns>The new value.</returns>
  public int Decrement()
  {
    return Interlocked.Decrement(ref _value);
  }
  /// <summary>Atomically add a value to the SharedInt.</summary>
  /// <param name="addend">The number to add to the SharedInt.</param>
  /// <returns>The new value.</returns>
  public int Add(int addend)
  {
    return Interlocked.Add(ref _value, addend);
  }
  /// <summary>Atomically replace the value of the SharedInt, returning the previous value.</summary>
  /// <param name="value">The number to set the SharedInt to.</param>
  /// <returns>The old value.</returns>
  public int Exchange(int value)
  {
    return Interlocked.Exchange(ref _value, value);
  }
  /// <summary>Atomically subtract a value from the SharedInt.</summary>
  /// <param name="subtrahend">The number to subtract from the SharedInt.</param>
  /// <returns>The new value.</returns>
  public int Subtract(int subtrahend)
  {
    return Interlocked.Add(ref _value, -subtrahend);
  }
}

int私はあなたが必要としないかもしれないいくつかの原子性保証が必要であり、同様にあなたが必要とするものを必要としないかもしれませんが、異なるクラス内から同じ値を処理できる手段として完全にうまく機能しました。

毎回プロパティを調べても構わない場合は、より汎用的なバージョンを実行できます。

public class TypedBox<T> where T : struct
{
  public T Value;
}

フィールドを公に公開することにはかなりの欠点があります (これが、私たちが一般的にそうしない理由です) 。またはパラメータとしてValuerefout

于 2012-09-04T23:40:04.263 に答える
1

あなたを完全に理解しているかどうかはわかりませんが、 of や 1-tuple などの参照型をラップするだけで済みintます。int[]1Tuple<int>

そう:

var a = Tuple.Create(10);
var b = Tuple.Create(15);
a = b;

Tuple<>ただし、はimmutableであるため、これはまったく無意味です。

しかし、次に:

var a = new[] { 10 };
var b = new[] { 15 };
a = b;
// a and b reference the same object, and that'a a mutable object!
b[0] = 17;
// now a and b are still the same object, so also a[0] == 17

注: これは、使用するrefキーワードとは関係ありません。ref何の理由もなく使っているようです。

于 2012-09-04T15:29:03.743 に答える