none
List<値型>の中の値を変更するには RRS feed

  • 質問

  • 初歩的なことなのですが、

    List<RectangleF> ar = new List<RectangleF>();
    ar.Add( new RectangleF( 0,0,10,10) );   
    ar[0].Offset( 100,100 );
       
    RectangleF rcf = ar[0];

    rcfは0,0,10,10になるのですが、100,100,110,110にする書き方はないでしょうか?

     

    2006年5月8日 8:41

すべての返信

  • とりあえず。う~ん、でももっとスマートな方法がありそうな気がする。(^^;

       RectangleF rcf = ar[0];
       rcf.Location = new PointF(ar[0].X + 100, ar[0].Y + 100);
       ar[0] = rcf;

    2006年5月8日 9:07
    モデレータ
  • 一旦変数に取り出して、その変数に対して Offset メソッドを適用した後に改めてリストに再代入すればいいでしょう。

    // こういう、自分自身を変更するメソッドは値型にはあって欲しくないなぁ……。変更済みの新しいインスタンスを返すようにしてくれないと。

    2006年5月8日 9:09
  • みなさん、どうもありがとうです。

    ちよっと間違ってました。幅と高さはかえないです。

    100,100,10,10にするスマートな書き方はないでしょうか、ということです。

    RectangleF [] ar2 = new RectangleF[1];
    ar2[0] = new RectangleF(0,0,10,10);
    ar2[0].Offset(100,100);

    RectangleF rcf = ar2[0];

    これだとrcfは100,100,10,10になるんですよね、、、。間違いやすいです。

     

    2006年5月8日 10:20

  • ちよっと間違ってました。幅と高さはかえないです。

    100,100,10,10にするスマートな書き方はないでしょうか、ということです。

    RectangleF [] ar2 = new RectangleF[1];
    ar2[0] = new RectangleF(0,0,10,10);
    ar2[0].Offset(100,100);

    RectangleF rcf = ar2[0];

    これだとrcfは100,100,10,10になるんですよね、、、。間違いやすいです


    どういうことでしょうか?理解できませんでした。

    期待している動作は何で、実際何になっているから困っているのですか?

    2006年5月8日 10:51
  • List<RectangleF> ar1 = new List<RectangleF>();
    ar1.Add( new RectangleF( 0,0,10,10) );   
    ar1[0].Offset( 100,100 );
       
    RectangleF [] ar2 = new RectangleF[1];
    ar2[0] = new RectangleF(0,0,10,10);
    ar2[0].Offset(100,100);

    RectangleF rcf1 = ar1[0]; // X=0,Y=0,WIDTH=10,HEIGHT=10
    RectangleF rcf2 = ar2[0]; // X=100,Y=100,WIDTH=10,HEIGHT=10

    質問の趣旨はrcf1もX=100,Y=100,WIDTH=10,HEIGHT=10にするスマートな書き方

    はないでしょうか、ということです。

    2006年5月9日 2:16
  • なかなか難しい問題ですね。
    Hongliangさんが書かれているように、値型の内容を書き換えるようなメソッドがあるのが紛らわしいという考えもありますが、オブジェクト指向的にはそのようなメソッドはあってもよいとは思えます。
     
    > スマートな書き方はないでしょうか、ということです。
     
    値型はコンテナから取り出した時点で異なるインスタンスのコピーであるので、格納されているインスタンスを直接操作することができない時点で、「取り出す」「変更する」「格納しなおす」という手順がどうしても必要です。
     
    変な記述としては、

    class=inlineLink onclick="window.open('/MSDN-JA/User/Profile.aspx?UserID=68882&SiteID=7', target='_self')">ar1 = ar1.ConvertAll(delegate(RectangleF src)
    class=inlineLink onclick="window.open('/MSDN-JA/User/Profile.aspx?UserID=68882&SiteID=7', target='_self')">{
    class=inlineLink onclick="window.open('/MSDN-JA/User/Profile.aspx?UserID=68882&SiteID=7', target='_self')">  src.Offset(100, 100);
    class=inlineLink onclick="window.open('/MSDN-JA/User/Profile.aspx?UserID=68882&SiteID=7', target='_self')">  return src;
    class=inlineLink onclick="window.open('/MSDN-JA/User/Profile.aspx?UserID=68882&SiteID=7', target='_self')">});
    class=inlineLink onclick="window.open('/MSDN-JA/User/Profile.aspx?UserID=68882&SiteID=7', target='_self')">
     
    みたいな方法もあるでしょうけど、まったくオススメできないです。
     
    2006年5月11日 18:42
  • ボックス化したものは,キャストで戻した地点とかで別物になってしまうし。
    値型を参照型にしてしまうような手段があってもよさそうなんですけどね...
     Ref<T> なクラスとか。
    参照型の RectangleF を自分で作って,それを利用とかになるんでは。

     

    2006年5月12日 1:45
  • みなさん、どうもありがとうございます。

    List<RectangleF> ar1 = new List<RectangleF>();
    ar1.Add( new RectangleF( 0,0,10,10) );   
    ar1[0].Location = new PointF(100,100); これはエラー

    これがコンパイルエラーになるのだから、スジとしてはOffsetもエラーになるべき、と思いますが、、、。

    List<RectangleF> ar1 = new List<RectangleF>();
    ar1.Add( new RectangleF( 0,0,10,10) );   
    RectangleF rc = ar1[0];
    rc.Offset( 100,100 ); // void関数なのだ
    ar1[0] = rc; 

    やはり、これしかないようですね。いまのところは。

     

    2006年5月16日 2:09
  • 上の Lady.BUGさんのコメントがスルーされてしまっているみたいだけど

    > ar1[0].Location = new PointF(100,100); これはエラー

    は,ar1[0] の時点ですでに要素のコピーが返ってきているから,
    その地点で別物になってしまっています。
    (エラーになっているのは,一時的な値型を変更しようとしているからなんだけど,
    たとえできたとしても,別物だから意味がないですよね)

    例えば,int のような同じ値型を扱ったとしても,
    C++でいうところの vector の [] は,参照を返す形(int&)だけど,
    BCL の List の [] は,値のコピーが返ってくる形(int)になっているため,
    動作が異なるんですよね...。

     

    # そもそも,CLR で値型の参照(いわゆる int& のようなもの)が可能なのか?
    # なぞですが...

    2006年5月18日 19:25
  •  稍丼 さんからの引用

    # そもそも,CLR で値型の参照(いわゆる int& のようなもの)が可能なのか?
    # なぞですが...

     
    .NET では、マネージドポインタ (int&) があるので可能です。
    ただし、CLSCompilantではなくなりますし、マネージドポインタはC#からはパラメータ以外では直接利用できないので難しいです。
     
    C#でマネージドポインタを扱えるのはパラメータだけで、キーワード ref を利用します。イメージ的には、

    (A)
    List<ref int> numberList = new List<ref int>;
     
    numberList.Add(new int(5));
    numberList[0] += 2;
    // もしくはunsafeの構文をまねて *(numberList[0]) += 2 かな?
     
    (B)
    public class RefList<T>
    {
      public ref int this[int index] { get; set; }
    }

     
    みたいなかたちで扱えればよいんでしょうけど、これはこれで「格納されている値型が、どこで確保されたメモリブロックへのポインタなのか?」をコンシューマが予測するのが非常に難しくなると思います。
    # スタックに確保された値を add したらその時点でヒープにコピーが生成されるとか、コンパイルエラーになるようなルールも必要かもしれないですね
     
    この続きは blog で(ぇ
    2006年5月19日 20:10
  • パラメータでの ref 指定がそれに相当するんですね。
    C#でやれなくても,ILで書けば,いろいろと検証可能なわけか...
    って,なんか,すごい先まで行っちゃってますね。

    2006年5月23日 2:09