views:

201

answers:

3

I have a custom list which inherits from Generic.List<T> like this:

public class TransferFileList<T> : List<TransferFile> { .. }

When I set (where 'Files' is a TransferFileList<T>):

var files = uploadResponse.Files.Where(x => !x.Success).ToList()

the 'files' object resolves as System.Collections.Generic.List<TransferFile>, not TransferFileList<T>, which is what I would expect as it was what was being filtered through the Where, so how could I successfully return a list of TransferFileList<T> into 'files'?

I did try:

var files = uploadResponse.Files.Where(x => !x.Success).ToList() 
as TransferFileList<TransferFile>;

but using that safe cast, it just resolves as null.

Thanks guys and gals.

+1  A: 

You can add an extension method for IEnumerable<TransferFile> to handle that scenario:

public static TransferFileList ToTransferFileList(
    this IEnumerable<TransferFile> files)
{
    return new TransferFileList(files);
}

// ...

var files = uploadResponse.Files.Where(x => !x.Success).ToTransferFileList();

This provides you with the TransferFileList instead of just a List<TransferFile>. Note the reason your as returns null is because while TransferFileList is a List<TransferFile>, the same does not hold in the other direction. That is, your List<TransferFile> is NOT a TransferFileList object.

I agree with @RexM that any attempt at subclassing List<T> be avoided due to the multitude of pitfalls associated. I suggest Composition (Has-A rather than Is-A) or sticking with the base class library collections instead.

sixlettervariables
Downvote reason?
sixlettervariables
(15 letter spacer) Not me.
GONeale
We don't know if TransferFileList has no ctor that takes a sequence, and even if it did, it's treating the symptom not the cause of the problem.
Rex M
He may genuinely need additional functionality found in `TransferFileList`. I agree though that composition would serve him better than inheritance.
sixlettervariables
Thanks for your help six.
GONeale
+2  A: 

First, I have to ask why you are inheriting from List<T>? 99% of the time that's a bad idea.

If you want to extend the functionality of a list, use extension methods:

public static something PrintErrors(this List<TransferFile> list)
{
    //do your printing logic
}

On to the answer: ToList() operates on an IEnumerable<T> and converts the members of the sequence to a List of the same type. Since you inherit from List<T> which implements IEnumerable<T>, that's what happens there.

Where() works the same way - operates on an IEnumerable<T> and returns an IEnumerable<T>.

To get some arbitrary list-like object back, like you have, you need to add the items in a sequence to your custom list, like so:

var myFiles = new TransferFileList<TransferFile>();
myFiles.AddRange(originalFileList.Where(condition));
Rex M
Why is it bad Rex? Hopefully I'm 1% :) I have a PrintErrors() method which returns any of my response's attached errors as a print-friendly string.
GONeale
@GONeale because nothing works like you expect it to when you inherit from List, just like this situation. See my revised answer for an alternative.
Rex M
Very good point there Rex on the x-method, however can they touch instance variables? I don't think so as they exist outside of the instance, I have a line like this in printErrors:<pre>string internalErrorMessage = StoreErrorBase.GetMessage(file.Error);</pre> (file.Error) being an 'Error' property on the instance of 'TransferFile'.
GONeale
@GONeale an extension method on a list has access to all the public members of the underlying list and all the items in the list.
Rex M
Thanks Rex, reluctantly I guess I have to introduce a new variable and new list assignment like you state. No problem though if it's the preferred method!
GONeale
@Rex oh yes, of course, silly me, obviously being in 'list' specified above with the 'this' attribute.
GONeale
@Rex Well! Maybe moving to an extension method might be best now! Thanks for your help.
GONeale
Worked a treat! and uses less memory :p, thanks!
GONeale
@GONeale cheers mate
Rex M
A: 

Thanks guys.

I like SLV's extension approach, but is there any other straight casting approach?

If not I might just go with the reverted in-line approach I was hoping to avoid:

var transferFiles = new TransferFileList<TransferFile>();
if (files != null) 
  transferFiles.AddRange(files);
GONeale