3

配列内の多数のショーツへの参照を保持したいと思います。ショーツを作成してから配列に追加するだけでよいと思いました。そのため...参照されるオブジェクトが変更されるたびに、これは配列に反映され、その逆も同様です。いくつかの試行を行って、そのようにはうまくいかないことを確信しました. 実際、値は転送されているように見えますが、参照ではありません。

以下のコードは、2 つの short を作成し、これらをオブジェクトとして配列に追加してから、元の short を変更します。ただし、配列内の想定された参照された short にアクセスすると、それは変更されていないため、元のオブジェクトとは何の関係もないまったく新しいオブジェクトであると私は信じています。

        Console.WriteLine("Testing simple references:");
        short v1 = 1;
        short v2 = 2;
        object[] vs = new object[2];
        vs[0] = v1;
        vs[1] = v2;
        v1 = 1024;
        v2 = 512;
        Console.WriteLine(" v1: " + (short)vs[0]);
        Console.WriteLine(" v2: " + (short)vs[1]);

ここで基本的なことを誤解しています。誰かが説明してくれれば幸いです。おそらく、私が望むことを行う解決策を教えてください。

4

6 に答える 6

18

C# の型体系には、「値型」と「参照型」の 2 種類の型があります。

値型は値によってコピーされます。1 つをコピーすると、元のオブジェクトとは何の関係もないまったく新しいオブジェクトが得られます。

参照型は参照によってコピーされます。1 つをコピーすると、実際には、あるストレージの場所への参照がコピーされます。どちらも 1 つのオブジェクトを参照する 2 つの参照を取得します。

Shorts は値型です。

short を参照型にしたい場合は、参照型ラッパーを作成できます。

class ReferenceType<T> where T : struct
{
    public T Value { get; set }
    public ReferenceType(T value) { this.Value = value; }
}

var v1 = new ReferenceType<short>(1);
var v2 = new ReferenceType<short>(2);
var vs = new ReferenceType<short>[2] { v1, v2 };
v1.Value = 1024;
v2.Value = 512;
Console.WriteLine(vs[0].Value);
Console.WriteLine(vs[1].Value);

そして、そこに行きます。

これで、shortへの参照アクセスが可能になります。これは、short が実際にはクラスの value プロパティに関連付けられたフィールドに格納されているためです。次に言う場合:

v2 = new ReferenceType<short>(3);
Console.WriteLine(vs[1].Value);

「3」は得られません -- v2 は vs[1] とは異なるオブジェクトを参照するようになりました。本当にキャプチャしたいものが変数への参照である場合、使用したいのはクロージャーです。

class ReferenceToVariable<T>
{
    private Func<T> getter;
    private Action<T> setter;
    public ReferenceToVariable(Func<T> getter, Action<T> setter) 
    { 
        this.getter = getter;
        this.setter = setter;
    }
    public T Value { get { return getter(); } set { setter(value); } }
}
...
short v1 = 1;
short v2 = 2;
var vs = new [] 
{ 
    new ReferenceToVariable<short>(()=>v1, x=>{v1=x;}),
    new ReferenceToVariable<short>(()=>v2, x=>{v2=x;})
};
v1 = 123;
vs[1].Value = 456;
Console.WriteLine(vs[0].Value); // 123
Console.WriteLine(v2); // 456

ここでは、v1 と v2 の現在の値を取得および設定する方法を知っている配列オブジェクトをキャプチャします。

ここで、別の変数に直接エイリアスを作成したい場合、このオブジェクトを邪魔しない場合、C# でそれを行う方法は 1 つしかありません。

void M(ref short x)
{
    x = 123;
}
...
short y = 1;
M(ref y);

現在、「x」と「y」は同じ変数の 2 つの名前です。ただし、「別の変数にエイリアスを作成する」という概念は、エイリアス変数がメソッドの仮パラメーターである場合にのみ C# で機能します。一般的には仕方がありません。

さて、理論的には、あなたが望むようなことをすることができます. 「ref locals」をサポートできます。


更新: ここで説明する「理論上の」機能は、C# 7.0 に追加されました。


short v1 = 1;
ref short rv1 = ref v1;
rv1 = 123;
Console.WriteLine(v1); // 123

つまり、rv1 は v1 のエイリアスになります。C# はこれをサポートしていませんが、CLR はサポートしているため、サポートできます。ただし、CLR は、"ref" 要素型の配列、または ref を格納するフィールドの作成をサポートしていません。そういう意味では、やりたいことができなかった。

C# は、変数への参照のように機能するオブジェクトを渡すための特別な「隠し」機能をサポートしていますが、上記の「2 つのデリゲート」参照よりも軽量です。ただし、これらの特別な機能は奇妙な相互運用シナリオ専用であり、使用しないことをお勧めします。(繰り返しになりますが、型付き参照を格納する配列を作成することはできません。) この回答では、これらの機能についてこれ以上説明することはないと思います。あなたは本当にそこに行きたくない、私を信じてください。

于 2011-02-04T16:36:37.750 に答える
5

Short値型ですが、参照型のように動作させようとしています。

プロパティを持つクラスを作成し、shortそのクラスの配列を使用できます。

public class MyShort
{
    public short Value {get; set;}
}

public class SomeOtherClass
{
   public void SomeMethod()
   {
       MyShort[] array = new MyShort[2];
       array[0] = new MyShort {Value = 5};
       array[1] = new MyShort {Value = 2};

       array[0].Value = 3;
   }
}

よりスムーズにするために、そこにできる作業がいくつかある可能性がありshortます(ラッパークラスとの間のコンバーターを実装するなど)。

于 2011-02-04T16:36:06.157 に答える
3

short型は値型であり、ショーツの動作を期待しているように動作する参照型のようには機能しません。値の型を変数に割り当てると、参照ではなく値が割り当てられます。vs[0]に割り当てた値のコピーを保持しますv1

元の値を変更したときに配列内の値を変更する必要がある場合は、short を参照型でラップする必要があります。次に例を示します。

public class ShortHolder {
  public short Value { get; set; }
}

次に、次のように使用できます。

var v1 = new ShortHolder() { Value=123; }
var shortArray = new ShortHolder[1];
shortArray[0] = v1;

あなたが変わればv1.ValueshortArray[0].Value変わる。

于 2011-02-04T16:37:09.900 に答える
1

値型は、メソッドに渡されるとき、または = 演算子を介して割り当てられるときに値によって渡されるため、値型と呼ばれます。

それを見るもう1つの(そしてより正しい)方法は、shorts、intなどは不変=>変更できないということです。したがって、基本的にショートを変更することはできません。どこかを変更するために short 型のオブジェクトが必要な場合は、このオブジェクトを保持するクラスを次のように作成する必要があります。


public class ShortWrapper
{
    public short ShortValue {get; set;}
}
class Program
{
    static void Main(string[] args)
    {
        ShortWrapper short1 = new ShortWrapper{ ShortValue = 1};
        ShortWrapper short2 = new ShortWrapper { ShortValue = 2 };

        ShortWrapper[] shorts = new ShortWrapper[] { short1, short2 };
        shorts[0].ShortValue = 5;

        Console.WriteLine(short1.ShortValue);
    }
}

基本的に、コードは short 型のオブジェクトを新しいオブジェクトに置き換えています。

ところで、裸のショートパンツを包む必要がある場合、デザインに何か問題がある可能性があります. より複雑なオブジェクトをすでに使用しているか、他の方法で short の配列を操作している必要があります。しかし、私はあなたがちょうどテストしていると思います。

于 2011-02-04T16:39:39.597 に答える
0

根本的な問題は、それshortがオブジェクトではなく構造体であることです。したがって、基本的にの配列は、short実際にはの配列でshortあり、短いオブジェクトへの参照の配列ではありません。

この問題を解決するには、ショートをクラスに「ボックス化」します (ただし、面倒です)。

以下を試してください。

public class MyShort { public Value { get; set; } }
于 2011-02-04T16:34:22.757 に答える