Joan Venge
Joan Venge

Reputation: 331370

Is it possible to have a property that is IEnumerable<T>?

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.

Upvotes: 7

Views: 1534

Answers (7)

Jon Hanna
Jon Hanna

Reputation: 113352

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).

Upvotes: 0

Yuriy Faktorovich
Yuriy Faktorovich

Reputation: 68737

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.

Upvotes: 4

mqp
mqp

Reputation: 72005

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.

Upvotes: 10

user7116
user7116

Reputation: 64118

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).

Upvotes: 1

Lasse Espeholt
Lasse Espeholt

Reputation: 17792

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);

Upvotes: 1

Dave Swersky
Dave Swersky

Reputation: 34810

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.

Upvotes: 1

Fredrik M&#246;rk
Fredrik M&#246;rk

Reputation: 158379

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

Upvotes: 2

Related Questions