2010-08-10 55 views
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中創建匿名類非常棒,但是迫使我在一行中進行計算。想象一下,calc比我顯示的要長。但它是類似的,我會做一些字典查找來獲得特定的值。調試可能會很痛苦。

具體類的使用解決了使用臨時變量的這個問題,但是我不能簡潔地做所有事情。是的,我意識到我在說我在尋求簡潔性,同時要求能夠在我的LINQ語句中保存臨時變量時有點矛盾。

我在循環點時開始嘗試創建一個匿名類,但很快就意識到我無法存儲它!你不能使用一個列表,因爲這會丟失整個班級的匿名性。

任何人都可以建議一種方法來實現我在找什麼?還是一些中間地帶?我已經在StackOverflow上閱讀了其他一些問題,但沒有一個與我的完全相同。

回答

5

假設我正確理解你,問題是你必須在單個表達式中設置所有的屬性。匿名類型絕對是這種情況。

但是,您不必在表達式中全部內聯。我建議,如果你的屬性是基於複雜的表達式,你打破那些表達出到輔助方法:

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

這具有額外的潛在益處,你可以每個輔助方法單元測試獨立,如果你」成爲白盒測試的粉絲(我是)。

這不會避免存在一個大的匿名類型初始化表達式,但它意味着工作將被打破。

+0

你確實瞭解我。感謝您爲我確認這一點,並且您的想法聽起來很棒! – Dave 2010-08-10 18:15:01

1

匿名類實際上旨在簡化處理lambdas的東西,尤其是LINQ。你想要做的事聽起來更適合嵌套的私人類。這樣,只有你的班級真正瞭解​​你的臨時班。試圖用匿名類來解決問題似乎只會使代碼複雜化。