2010-08-10 53 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。你想要做的事听起来更适合嵌套的私人类。这样,只有你的班级真正了解​​你的临时班。试图用匿名类来解决问题似乎只会使代码复杂化。