views:

127

answers:

3

Here is your basic DataSource override:

    public override object DataSource
    {
        get
        {
            return base.DataSource;
        }
        set
        {   
            base.DataSource = value;
        }
    }

What I would like to do in the setter method is cast value to IEnumerable<> and do some manipulations on it (or throw an exception if I can't cast it to IEnumerable<>) and then pass that into base.DataSource. Any help in accomplishing this would be appreciated.

+1  A: 

You didn't mention .net version, but linq provides a AsEnumerable() method that does what you are looking for.

The useage would be value.AsEnumerable<type>()

See here

David Culp
Thanks for the fast responses. I learned a lot just from reading all of them.I explained what I need/want very poorly. Sorry, I'm a StackOverflow newbie. First, I'm using .NET version 3.5, Visual Studio 2008 Professional. I've been tasked with creating a custom control that, for all intents and purposes, is a ListView that has a couple extra properties for setting the maximum number of rows that will be displayed. (If you're thinking "wouldn't you set that in the data layer", hey, it's their dime. The powers that be want to be able to set the maximum in the presentation layer, too.)
Krusaide
Consequently, I was thinking I would somehow override the DataSource property, maybe call a Take<T> in there, but I don't know what type "value" will be. That was the plan. All of you seem very bright, perhaps there's a better way to go about this... or some facet of the ListView that I am overlooking that already does this.
Krusaide
if what your wanting is something closer to paging, show first 10 then next 10 and so on. Might consider looking at asp.net's gridview and other similar controls that have paging already built in. If you are just wanting the first so many, it doesn't really matter what type the elements of the collection are, just grab those you want to use.
David Culp
A: 

You can get by with a simple type cast, as shown with several examples below. Note that you should be cautious entering into just any IEnumerable, as some enumerable classes have no concept of backing up once iterated. Lists and arrays will treat you fine, but some others pass a point of no return with every iteration.

public override object DataSource
{
    get { return base.DataSource; }
    set
    {   
        // Throws an exception if the cast won't work.
        var genenum = (IEnumerable<string>)value;

        // Non-generic enumerable collection, if generic is not necessary.
        // Still throws an exception if the cast is invalid.
        var nongenenum = (IEnumerable)value;

        // Alternatively, you can use a defensive type cast, and manually
        // throw an exception if the result is null or not able to be casted.
        var safeenum = value as IEnumerable<string>;
        if(safeenum == null) throw new ArgumentException();

        // or...
        if(!(value is IEnumerable<string>)) throw new ArgumentException();

        // ... Do stuff with the enumerable.

        base.DataSource = value;
    }
}
kbrimington
Thanks. I think the general idea is I have no idea what type to use the generic. I wanted to determine it at runtime. Something along the lines Type a = value.GetType(); IEnumerable<a> collection = (IEnumerable<a>)value; but that won't work for a number of reasons. I explained it very poorly. The goal is to limit the size of the data source for a ListView subclass.
Krusaide
@Krusaide: You can do that. Try this out (using System.Linq, of course): `var enumerable = ((IEnumerable)value).Cast<object>().Take(maximumCount);`. Of course, expand the statement out over a few lines so you can do proper null checking or exception handling on the cast. Good luck!
kbrimington
+1  A: 
public override object DataSource
{
    get
    {
        return base.DataSource;
    }
    set
    {   
        if (!(value is IEnumerable<MyType>))
            throw new InvalidOperationException(...); // or ArgumentException

        base.DataSource = (IEnumerable<MyType>) value;
    }
}

or perhaps...

    set
    {
        // Includes IEnumerable<T> for any T
        if (!(value is IEnumerable))
            throw new InvalidOperationException(...); // or ArgumentException

        // Do some processing on it, for example cast to your type?
        base.DataSource = ((IEnumerable) value).Cast<MyType>();
    }
Timwi
Let me go into a little more detail. I'm overriding the ListView control so that you can limit the number of rows that are displayed. Again, you would think you just do that in the data layer or business layer that gets the collection in the first place, but they don't want that. It has to be a property on the control itself. I wanted to use Type a = value.GetType(); IEnumerable<a> = (IEnumerable<a>)value; or something along those lines, but there's probably a better way. I think I may be onto something from your second example, though.
Krusaide