views:

159

answers:

7

I have a class that's IEnumerable<T> where I want to have different properties that provides a filtered IEnumerable<T> access.

So for instance:

class Shape
   ShapeType = Box/Sphere/Pyramid

class ShapeCollection : IEnumerable<Shape>
{
   public IEnumerable<Shape> OnlyBox
   {
       foreach(var s in this)
       {
           if (s.ShapeType == Box)
               yield return s;
       }
   }
}

Is this how it should be? Just not sure, about it completely.

Thanks.

+2  A: 

Sure, that should work (as far as I can see) even though @mquander's solution might be a tad more elegant.

Fredrik Mörk
+11  A: 

Sure, but you might want to rewrite it as

public IEnumerable<Shape> OnlyBox
{
    get { return this.Where(x => x.ShapeType == ShapeType.Box); }
}

which does the exact same thing.

mquander
+1 for expressiveness.
Cumbayah
Thanks, yeah this was a bit flaky in my mind. Now I can see it clearly.
Joan Venge
WTG w/ LINQ FTW.
Randolpho
+1  A: 

This is valid, but redundant I think. If you want to expose a strongly-typed list of Shapes:

public class Shape
{

}

public class SomethingThatHasShapes
{
   public List<Shape> Shapes { get; set; }
   public Boxes
   {
      get { return Shapes.Where(s => s.ShapeType = ShapeType.Box); }
   }  


}

The List<T> class implements IEnumerable.

Dave Swersky
The downside of this is that it exposes your list to outside influences.
Chris Farmer
You need a return type on the your second property.
Jerod Houghtelling
+4  A: 
class ShapeCollection : IEnumerable<Shape>
{
   public IEnumerable<Shape> OnlyBoxes
   {
       get { return this.Where(s => s.ShapeType == Box); }
   }
}

You were missing the get/parenthesis to make it a method. Also what is Box, did you mean ShapeType.Box? Also maybe rename it to OnlyBoxes, seems more descriptive.

Yuriy Faktorovich
Nobody vote me up, my reputation is good the way it is.
Yuriy Faktorovich
Thanks I voted you. I wrote the code like that because I wasn't using VS and didn't want to write the whole thing.
Joan Venge
+1  A: 

Personally, I believe your OnlyBox property is redundant. Because the users of your class will always have the option to use Linq like the following with the same performance. So unless you can do it better than the Linq methods, I think it is fine to leave it to the user of the class like:

var filtered = shapeCol.Where(s => s.ShapeType == Box);

But if you want a property, instead of:

foreach(var s in this)
{
    if (s.ShapeType == Box)
        yield return s;
}

you could write:

return this.Where(s => s.ShapeType == Box);
lasseespeholt
Thanks, the idea was because this is simplified but in reality the code to filter is very ugly because this is a wrapper for unmanaged class. So wanted to make it a bit more high level for users and myself.
Joan Venge
+1  A: 

A more LINQ like fashion would be providing a method for your Collection:

public IEnumerable<Shape> Boxes()
{
    return this.Where(ss => ss.ShapeType == ShapeType.Box);
}

Or just having users do a Where clause:

// gather boxes
var query = from shape in shapes
            where shape.ShapeType == ShapeType.Box
            select shape;

Otherwise, nothing wrong with IEnumerable as a property (keeping in mind properties should be so simple they rarely throw exceptions).

sixlettervariables
A: 

Yep. What you have is good. You can do convert to lambda-based if you prefer its expressiveness, though the lambda version can sometimes be less performant (not so much that I'd change a lambda version to 2.0 style unless it proved problematic, but enough that I wouldn't change a perfectly good 2.0 style to lambda-based unless it made it a lot more expressive).

Jon Hanna