3

私は匿名のクラスに不慣れです、そして今日私は私が本当にそれらを使うことができると感じた最初のケ​​ースに出くわしたと思います。クラス内に一時データを格納することでメリットが得られるメソッドを作成しています。そのクラスはそのメソッドの外部では意味がないため、匿名クラスを使用することは確かに理にかなっています(少なくともその時点では)。

コーディングを始めた後、私は確かにいくつかの譲歩をしなければならなかったように見えました。計算などを一時変数に割り当てて、デバッグ中に論理チャンクで一度に計算のビットを検証できるようにするのが好きです。次に、より単純なものを最終値に割り当てたいと思います。この値は匿名クラスにあります。

問題は、匿名クラスを使用してコードを簡潔に実装するために、LINQを使用したいということです。ここでの問題は、ステートメント内でそのような一時的な計算を実行できないと思うことです。 またはあなたはできますか?

これが私がやりたいことの不自然な例です:

namespace AnonymousClassTest
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        ObservableCollection<RectanglePoints> Points { get; set; }

        public class RectanglePoints
        {
            public Point UL { get; set; }
            public Point UR { get; set; }
            public Point LL { get; set; }
            public Point LR { get; set; }
        }

        public class DontWantThis
        {
            public double Width { get; set; }
            public double Height { get; set; }
        }

        private Dictionary<string,string> properties = new Dictionary<string,string>();
        private Dictionary<string,double> scaling_factors = new Dictionary<string,double>();

        private void Sample()
        {
            // not possible to do temp variables, so need to have
            // longer, more unreadable assignments
            var widths_and_heights = from rp in Points
                                     select new
                                     {
                                        Width = (rp.UR.X - rp.UL.X) * scaling_factors[properties["dummy"]],
                                        Height = (rp.LL.Y - rp.UL.Y) * scaling_factors[properties["yummy"]]
                                     };

            // or do it in a for loop -- but then you have to use a concrete
            // class to deal with the Width and Height storage
            List<DontWantThis> other_widths_and_heights = new List<DontWantThis>();
            foreach( RectanglePoints rp in Points) {
                double base_width = rp.UR.X - rp.UL.X;
                double width_scaling_factor = scaling_factors[properties["dummy"]];
                double base_height = rp.LL.Y - rp.UL.Y;
                double height_scaling_factor = scaling_factors[properties["yummy"]];

                other_widths_and_heights.Add( new DontWantThis 
                                              { 
                                                  Width=base_width * width_scaling_factor,
                                                  Height=base_height * height_scaling_factor
                                              });
            }

            // now we want to use the anonymous class, or concrete class, in the same function
            foreach( var wah in widths_and_heights)
                Console.WriteLine( String.Format( "{0} {1}", wah.Width, wah.Height));
            foreach( DontWantThis dwt in other_widths_and_heights)
                Console.WriteLine( String.Format( "{0} {1}", dwt.Width, dwt.Height));
        }

        public Window1()
        {
            InitializeComponent();
            Points = new ObservableCollection<RectanglePoints>();
            Random rand = new Random();
            for( int i=0; i<10; i++) {
                Points.Add( new RectanglePoints { UL=new Point { X=rand.Next(), Y=rand.Next()  },
                                                  UR=new Point { X=rand.Next(), Y=rand.Next()  },
                                                  LL=new Point { X=rand.Next(), Y=rand.Next()  },
                                                  LR=new Point { X=rand.Next(), Y=rand.Next()  }
                                                } );
            }

            Sample();
        }
    }
}

注:実際に辞書にキーを追加しない限り、これを実行しようとしないでください:)

LINQでの匿名クラスの作成は素晴らしいですが、計算を1行で実行する必要があります。計算が私が示したものよりもはるかに長いと想像してください。しかし、特定の値を取得するためにいくつかの辞書ルックアップを実行するという点で似ています。デバッグは苦痛になる可能性があります。

具象クラスを使用すると、一時変数を使用するというこの問題を回避できますが、すべてを簡潔に行うことはできません。はい、LINQステートメントで一時変数を保存できるように要求しながら、簡潔さを求めていると言っているのは少し矛盾していることに気づきました。

ポイントをループするときに匿名クラスを作成しようとし始めましたが、すぐにそれを保存する方法がないことに気付きました!リストを使用することはできません。リストはクラスの匿名性全体を失うだけだからです。

誰かが私が探しているものを達成する方法を提案できますか?またはいくつかの中間点?StackOverflowで他のいくつかの質問を読みましたが、どれも私のものとまったく同じではありません。

4

2 に答える 2

5

私があなたを正しく理解していると仮定すると、問題は、すべてのプロパティを1つの式に設定する必要があるということです。匿名タイプの場合は間違いなくそうです。

ただし、その式ですべてをインラインで行う必要はありません。プロパティが複雑な式に基づいている場合は、それらの式をヘルパーメソッドに分割することをお勧めします。

var complex = new {
      First = ComputeFirstValue(x, y),
      Second = ComputeSecondValue(a, b)
      ...
};

これには、ホワイトボックステストのファンであれば、各ヘルパーメソッドを個別に単体テストできるという追加の潜在的な利点があります(私はそうです)。

これは、1つの大きな匿名型の初期化式が存在することを回避するものではありませんが、作業が分割されることを意味します。

于 2010-08-10T16:37:35.983 に答える
1

匿名クラスは、ラムダ、特にLINQを処理するものを単純化することを目的としています。あなたがやろうとしていることは、ネストされたプライベートクラスにはるかに適しているように聞こえます。そうすれば、あなたのクラスだけがあなたの一時クラスについて本当に知っています。匿名クラスをいじくり回そうとすると、コードが複雑になるだけのようです。

于 2010-08-10T16:44:24.443 に答える