none
List comes back NULL from LINQ expression RRS feed

  • Question

  • My goal:   filter out those in the list that satisfy the &&

    My problem:  I get null for itemList after it runs through the LINQ expressoin...when I know that if I debug and iterate through that LINQ check that 3 items in that list IS satisfying both those checks for the && so I should be getting 3 back in my itemList in the end.

    private ItemList someMethod(ItemList itemList)
    {
        ...
        itemList = items.Where(x => x.ItemType != ItemType.Car && x.ItemType != ItemType.Truck).ToList() as ItemList;
       
        return itemList;
        ....
    }

    ItemList is just a custom class that inherits from : List<Item>
    C# Web Developer
    Thursday, December 10, 2009 5:48 PM

Answers


  • Since ItemList is-a List, then why couldn't I case it up to ItemList in the end? I get a runtime error here saying: Unable to cast object of type 'System.Collections.Generic.List`1[List]' to type 'ItemList'. I probably still don't get the fundamental issue here so can we revisit this again?
    C# Web Developer

    Sure - I'll try to write this out again, using a different example.

    I'm going to do the class OO thing, and talk about this in terms of animals ;)

    Say you have that following classes:

    public class Animal
    {
       public bool IsAlive { get; set; }
    }
    
    public class Mammal : Animal
    {
       // Mammal specific things...
    }
    
    public class Cat : Mammal
    {
       public void Meow() { .... }
    }
    


    Now, when you declare these, you are free to assign any Cat to a variable declared as a Mammal or as an Animal:

    Cat cat = new Cat();
    
    Animal randomAnimal = cat; // Perfectly acceptable
    

    This is allowed because Cat is a subclass of Animal, hence a Cat IS-A specific type of Animal.

    However, the following is not allowed:

    Animal animal = GetSomeRandomAnimalType();
    
    Cat cat = animal; // Fails at compile time
    This fails because, although a Cat IS-A Animal, and Animal is not (necessarily) a Cat.  The "animal" variable, as far as the CLR and the compiler is aware, might not be a Cat - it might be any type of animal.  For example, it might actually be:

    class Frog : Animal
    {
    }
    
    // ....
    
    Animal GetSomeRandomAnimalType()
    {
        return new Frog(); // Uh-oh - we're no longer returning a Cat...
    }


    Now, if GetSomeRandomAnimalType() actually returned a cat, and we (as a developer) know it is returning a cat, we could do:

    Animal animal = GetSomeRandomAnimalType();
    
    Cat cat = (Cat)animal; // Succeeds at compile time, but may return InvalidCastException if "animal" is actually a Frog!
    
    Cat cat2 = animal as Cat; // Will succeed at compile time AND at runtime, but if "animal" is a Frog, you'll return null
    The reason this succeeds is that we're telling the compiler to force it to work.  However, if we're wrong, at runtime, we'll either throw (in the first case) or get null (in the second case).

    Now, let's look at your specific situation, and relate it.  You have the following:

    class ItemList : List<Item>
    {
    }
    
    

    When you run, you're creating a List<Item> here:

    List<Item> temporaryCreatedInline = items.Where(x => x.ItemType != ItemType.Car).ToList();
    However, you're trying to set this temporary variable to an ItemList class reference:

    ItemList list = temporaryCreatedInline; // Compiler failure!
    This is the same as if you did the following above:

    Cat cat = new Mammal(); // Fails!
    (ItemList == Cat and List<Item> == Mammal).

    Even if you put a cast in there, it doesn't change the fact that List<Item> is not actually an ItemList  - so you can't just directly cast this.  ItemList is a List<Item>, (just as Cat is a Mammal), but the opposite is not true.

    This, I agree, can be frustrating.  However, the core issue is that the CLR and the compiler cannot do what you are trying to do.  In your case, technically, an ItemList is basically equivelent to List<Item> (since you add no new fields, members, etc), but technically, it is not the same thing.  It would be a violation of basic object oriented principles in a strongly typed language to allow the cast to go through, since it would mean List<Item> would have to actually become an ItemList - even though it wasn't constructed as one.

    Granted, in dynamically typed languages that support some form of duck typing, this would work.  C#, however, is not a dynamically typed language - it is a fully static typed language, and does not allow this to go through.

    In your case, I recommended adding a new constructor to ItemList that took an IEnumerable<Item>.  This would let you create an ItemList from the LINQ statement, but you'd be creating a new instance of an ItemList class. 


    Reed Copsey, Jr. - http://reedcopsey.com
    • Marked as answer by NoEgo Friday, December 11, 2009 7:45 PM
    Friday, December 11, 2009 6:52 PM
    Moderator

All replies

  • Just to help figure out the problem ...

    If you put

    var x =

    On the left side of the equal sign and remove the "as ItemList", do you get the values in x?

    This should help define whether the problem is with the lamda expression or with the conversion to ItemList.

    Hope this helps.
    www.insteptech.com ; msmvps.com/blogs/deborahk
    We are volunteers and ask only that if we are able to help you, that you mark our reply as your answer. THANKS!
    Thursday, December 10, 2009 5:52 PM
  • if I put var newVariable = (that line) then I get back the entire list...it's not even filtering anything
    C# Web Developer
    Thursday, December 10, 2009 6:00 PM
  • So I would suggest taking it apart further:

    var newVariable =  items.Where(x => x.ItemType != ItemType.Car).ToList()

    Does this give you just the non-car items? Or does this still give you the entire list as well?
    www.insteptech.com ; msmvps.com/blogs/deborahk
    We are volunteers and ask only that if we are able to help you, that you mark our reply as your answer. THANKS!
    Thursday, December 10, 2009 6:07 PM
  • I have occasionally run into that problem with LINQ as well. It might actually be a bug, because, as far as I can tell, there is nothing syntactically wrong. You may as a test run your first LINQ query, then run the other just to confirm.

    //do this first, does it work?
    var newList = items.Where(x => x.ItemType != ItemType.Car).ToList();


    John Grove - TFD Group, Senior Software Engineer, EI Division, http://www.tfdg.com
    Thursday, December 10, 2009 6:07 PM
  • Deborah, it gives me back the entire list that I passed to the method in the first place if using var.  I'm essentially trying to do this which works as expected but through LINQ:


                ItemList filteredItemList = new ItemList();

                int index = 0;
                foreach(Item i in itemList)
                {
                    if(i.ItemType != ItemType.SomeEnumValue1 && i.ItemType != ItemType.SomeEnumValue2)
                        filteredPers.Add(p);

                    index++;
                }

                return filteredItemList;
    C# Web Developer
    Thursday, December 10, 2009 6:10 PM
  • So if you type this:

    var newVariable =  items.Where(x => x.ItemType != ItemType.Car).ToList()

    And look at newVariable, it contains all of the items in the list, including those with ItemType.Car?

    Is ItemType an Enum?

    Could you provide the definition of x.ItemType and ItemType so I could give it a try here?
    www.insteptech.com ; msmvps.com/blogs/deborahk
    We are volunteers and ask only that if we are able to help you, that you mark our reply as your answer. THANKS!
    Thursday, December 10, 2009 6:31 PM
  • There's a problem in your logic:

            itemList = items.Where(x => x.ItemType != ItemType.Car && x.ItemType != ItemType.Truck).ToList() as ItemList;

    Look at what this is doing:

    This portion:

        items.Where(x => x.ItemType != ItemType.Car && x.ItemType != ItemType.Truck)

    Will return an IEnumerable<Item>  (or whatever you individual Item class is called).

    You then call .ToList() on that result, which converts it to a List<Item>.

    Esentially, you're doing:

    List<Item> itemsTemp = items.Where(x => x.ItemType != ItemType.Car && x.ItemType != ItemType.Truck).ToList();
    ItemsList itemList = itemsTemp as ItemList;

    However, List<Item> is not a ItemList!  The as statement will return null, which in turn gives you a null.

    You can't case from a base class to a subclass (only the other way).  You'll need to construct a new ItemList instead.  I recommend adding a constructor to your ItemList class that takes an IEnumerable<Item>.  If you do that, you can do:

        ItemList itemList = new ItemList(items.Where(x => x.ItemType != ItemType.Car && x.ItemType != ItemType.Truck));

    This would avoid the ToList() call, and work.





    Reed Copsey, Jr. - http://reedcopsey.com
    • Proposed as answer by DeborahKMVP Friday, December 11, 2009 4:43 PM
    Thursday, December 10, 2009 6:36 PM
    Moderator
  • Yea, this is where I was trying to lead the OP as well.

    But from the other posts, it looks like there may be something wrong because the lambda expression itself does not appear to be working for him. He says he is getting the full list instead of the list where the type is not a car or a truck.


    www.insteptech.com ; msmvps.com/blogs/deborahk
    We are volunteers and ask only that if we are able to help you, that you mark our reply as your answer. THANKS!
    Thursday, December 10, 2009 6:56 PM
  • I think the problem may be the method call itself:


    private ItemList someMethod(ItemList itemList)
    {
        ...
        itemList = items.Where(x => x.ItemType != ItemType.Car && x.ItemType != ItemType.Truck).ToList() as ItemList;
       
        return itemList;
        ....
    }


    Note the difference.  You're not showing us the entire method, but it may be that you're calling this method, but applying the filter on a different collection (looking at the code).

    I suspect this should be:

    private ItemList someMethod(ItemList itemList)
    {
        var tempList = itemList.Where(x => x.ItemType != ItemType.Car && x.ItemType != ItemType.Truck);
        return new ItemList(tempList); // Would require an IEnumerable<T> addition to the ItemList constructor
    }


    Reed Copsey, Jr. - http://reedcopsey.com
    Thursday, December 10, 2009 7:05 PM
    Moderator
  • ItemList is merely a custom class that inherits from : List<Item>.  So I should be able to somehow cast it to ListItem

    C# Web Developer
    Friday, December 11, 2009 12:59 PM
  • No. You cannot. (Believe me, I have tried since all of my list classes inherit from BindingList and all need to do lambda expressions like you are doing.)

    You have to do something like what Reed provided using a constructor.

    Hope this helps.
    www.insteptech.com ; msmvps.com/blogs/deborahk
    We are volunteers and ask only that if we are able to help you, that you mark our reply as your answer. THANKS!
    Friday, December 11, 2009 4:43 PM
  • ItemList is merely a custom class that inherits from : List<Item>.  So I should be able to somehow cast it to ListItem

    C# Web Developer

    Basically, when you subclass a specific class, you're making a more concrete type.  In your case, you're doing:

    ItemList : List<Item>

    By doing this, you're saying that ItemList is a specific type of List<Item>.  Because of this, anywhere you have a variable declared List<Item>, you can substitute out an instance of ItemList.  That makes this valid:

    List<Item> list = new ItemList(); // ItemList is-a List<Item>, so this is valid.

    However, the opposite isn't true:

    ItemList list = new List<Item>(); // This fails at compile time!

    The problem is that List<Item> is not a ItemList.  You could have added other fields, methods, and properties to your ItemList class that didn't exist in List<item> (and probably did, otherwise, there'd be no reason for a subclass here - just use List<Item>!).  When you try to assign this, that "extra" information is missing, because List<Item> is not an ItemList.

    For details, I suggest you read up on the Liskov substitution principle, Covariance and Contravariance, and Subtyping Polymorphism.


    Reed Copsey, Jr. - http://reedcopsey.com
    Friday, December 11, 2009 4:56 PM
    Moderator
  • Reed, I've had a crapload of problems with my boss implementing lists like this.  He refuses to use lists by just typing List<whatever> and feels he has to for some odd reason create a custom class that inherits from List<whatever> I guess because he in my opinion is a lazy coder and to him typing List<> is too much work.

    And even worse 99% of the time his custom type does NOT have any additional members so what's the point in doing this if you're not adding any additional value by doing so?  Why not just use plain List<type> and any additional helper methods just make them extension methods.  I don't get the point in that every List<CustomType> he feels the need to automatically create a class CustomType : List<CustomType> for it and use that instead of plain List<CustomType> when CustomType has no fricking members in it!  I mean is he thinking this is a holder in case anyone wants to extend it later therefore force that convention in the application so we don't have any List<Type> floating around?  I guess I'd have to ask him but seriously his reasons are flawed half the time due to laziness or weird decisions/reasons so I don't feel like battling this one.

    Well, this has created a huge problem for me.  I LIKE typing List<> and so I get all sorts of cast problems becasue the compiler still tells me it can't cast to that type even though I'm for instance doing something like this:

    (List<Something>)SomethingList

    here I want to use regular standard syntax and knowing that his SomeList is really this below, I still get casting problems that the compiler complains saying it can't cast to that type:

    SomethingList : List<Something>

    So I'm probably a victim of like you say List<Something> is not a SomethingList but SomethingList is a List<Something> so I am able to cast up to List<Something> from a SomethingList but I can't cast up from a List<Something> to a SomethingList, is that what you're saying?

    C# Web Developer
    • Edited by NoEgo Friday, December 11, 2009 5:34 PM
    Friday, December 11, 2009 5:16 PM
  • And Reed, I read your previous post before that. Adding an IEnumerable constructor. But since ItemList inherits from List wouldn't that make ItemList alreayd enumerable? this is so G. Damn frustating that he made all his lists custom types.

    I think now I will have to go through and add an IEnumerable constructor like you said to these custom types that simply inherit from List just to get them to work instead of if we were just using List to begin with that all I would have to do is this below right?

      List<Item> list = items.Where(x => x.ItemType != ItemType.Car && x.ItemType != ItemType.Truck).ToList(); that would work right?

    But because I'm trying to return an ItemList to satisfy his weird ____ custom list classes, I end up having to produce necessary code just because he wants to use these fancy easy MyEasyNameList custom types instead of just typing List.

    Sorry, this a rant, however it's just been a HUGE annoyance even outside of LINQ trying to cast. I think partly it's me not understanding but also the convention that he's using makes no sense...just use List! No point in creating a custom type just to make a list easy to type! I mean has anyone here done that? Created a class that inherts from List<> when that custom class has no members or value or reason to do so?

    I mean I can't go through the entire codebase now and change any references to CustomTypeList back to List...it would be a chore and he'd kill me anyway. I just think it was a very poor decision to do this in the first place.
    C# Web Developer
    Friday, December 11, 2009 5:29 PM
  • Now I guess I know how people feel that take over my code ... because I do this as well.

    I have a base BindingList<T> class. *ALL* of my business objects then have a class that inherits from this base class.

    So I have Customer/Customers (plural), Product/Products, and so on.

    I *do* have several features implemented in my base class, however, such as a DeletedItems list to track delete items until the user selects to save them. I also handle the sorting so binding to these classes can be sored in a DataGridView.

    So I find this to be very useful.

    I'm sure this does not help. :-(

    But I wanted you to know that there are others stuck with this type of code as well.
    www.insteptech.com ; msmvps.com/blogs/deborahk
    We are volunteers and ask only that if we are able to help you, that you mark our reply as your answer. THANKS!
    Friday, December 11, 2009 5:43 PM
  • public class ItemList : List { } private ItemList FilterOutNonApplicableItems(ItemList itemList) { List filteredItemlist = itemList.Where(x => x.DispType != ItemDispType.Item && x.DispType != ItemDispType.Comments).ToList(); //ItemList filteredItemList = new ItemList(); //int index = 0; //foreach(Item i in itemList) //{ // if(i.DispType != ItemDispType.Item && i.ItemType != ItemDispType.Comments) // filteredPers.Add(p); // index++; //} return (ItemList)filteredItemList; } I just don't get why this doesn't work again. Here's a better example of code. I would assume in the above per your comments Reed that since I'm setting the results of the LINQ ToList() that I could set it to that List. Since ItemList is-a List, then why couldn't I case it up to ItemList in the end? I get a runtime error here saying: Unable to cast object of type 'System.Collections.Generic.List`1[List]' to type 'ItemList'. I probably still don't get the fundamental issue here so can we revisit this again?
    C# Web Developer
    Friday, December 11, 2009 5:44 PM
  • What's up with the editor in these forums?  IT keeps unformatting my text and there's no rhyme or reason for it.  When I go to edit, sometimes it throws all my text back into one blog paragraph!

    Anyway,

        public class ItemList : List<Item>
        {

        }



            private ItemList FilterOutNonApplicableItems(ItemList itemList)
            {
                List<Item> filteredItemlist = itemList.Where(x => x.DispType != ItemDispType.Item && x.DispType != ItemDispType.Comments).ToList();

                //ItemList filteredItemList = new ItemList();

                //int index = 0;
                //foreach(Item i in itemList)
                //{
                //    if(i.DispType != ItemDispType.Item && i.ItemType != ItemDispType.Comments)
                //        filteredPers.Add(p);

                //    index++;
                //}

                return (ItemList)filteredItemList;
            }

    Now per the above again, I just don't get why this doesn't work again. Here's a better example of code. I would assume in the above per your comments Reed that since I'm setting the results of the LINQ ToList() that I could set it to that List.

    Since ItemList is-a List, then why couldn't I case it up to ItemList in the end? I get a runtime error here saying: Unable to cast object of type 'System.Collections.Generic.List`1[List]' to type 'ItemList'. I probably still don't get the fundamental issue here so can we revisit this again?
    C# Web Developer
    C# Web Developer
    Friday, December 11, 2009 5:47 PM
  • Thanks Deborah.

    I can see doing that if you want to extend the generic List class of .NET.  But if you're not and then furthermore not adding any real value by just creating a custom class that inherits that LIst<Type> then your entire codebase is now reliant on your custom type just to create and use simple generic lists and you're stuck with all sorts of issues like what I am finding here as well as having cast issues (most likely I'm trying to cast wrong like Reed says, but if I just had a basic List<> I wouldn't have to deal with the custom ClassList type anyhow).
    C# Web Developer
    Friday, December 11, 2009 5:49 PM
  • In C#, there is no "typedef", so this kind of derivation is sometimes used as a kind of "renaming".

    In some cases, it's clearly not necessary:
      Products : List<Product> { }
    In other cases, it's much more helpful:
      Grades : List<int> { }

    If used properly, this technique can enhance the readability of the code.

    That said, I never use it. ;)

            -Steve


    Programming blog: http://nitoprograms.blogspot.com/
      Including my TCP/IP .NET Sockets FAQ

    Microsoft Certified Professional Developer
    Friday, December 11, 2009 6:12 PM
  • Here is an interesting discussion of Collection covariance with C# 4.0


    John Grove - TFD Group, Senior Software Engineer, EI Division, http://www.tfdg.com
    Friday, December 11, 2009 6:24 PM

  • Since ItemList is-a List, then why couldn't I case it up to ItemList in the end? I get a runtime error here saying: Unable to cast object of type 'System.Collections.Generic.List`1[List]' to type 'ItemList'. I probably still don't get the fundamental issue here so can we revisit this again?
    C# Web Developer

    Sure - I'll try to write this out again, using a different example.

    I'm going to do the class OO thing, and talk about this in terms of animals ;)

    Say you have that following classes:

    public class Animal
    {
       public bool IsAlive { get; set; }
    }
    
    public class Mammal : Animal
    {
       // Mammal specific things...
    }
    
    public class Cat : Mammal
    {
       public void Meow() { .... }
    }
    


    Now, when you declare these, you are free to assign any Cat to a variable declared as a Mammal or as an Animal:

    Cat cat = new Cat();
    
    Animal randomAnimal = cat; // Perfectly acceptable
    

    This is allowed because Cat is a subclass of Animal, hence a Cat IS-A specific type of Animal.

    However, the following is not allowed:

    Animal animal = GetSomeRandomAnimalType();
    
    Cat cat = animal; // Fails at compile time
    This fails because, although a Cat IS-A Animal, and Animal is not (necessarily) a Cat.  The "animal" variable, as far as the CLR and the compiler is aware, might not be a Cat - it might be any type of animal.  For example, it might actually be:

    class Frog : Animal
    {
    }
    
    // ....
    
    Animal GetSomeRandomAnimalType()
    {
        return new Frog(); // Uh-oh - we're no longer returning a Cat...
    }


    Now, if GetSomeRandomAnimalType() actually returned a cat, and we (as a developer) know it is returning a cat, we could do:

    Animal animal = GetSomeRandomAnimalType();
    
    Cat cat = (Cat)animal; // Succeeds at compile time, but may return InvalidCastException if "animal" is actually a Frog!
    
    Cat cat2 = animal as Cat; // Will succeed at compile time AND at runtime, but if "animal" is a Frog, you'll return null
    The reason this succeeds is that we're telling the compiler to force it to work.  However, if we're wrong, at runtime, we'll either throw (in the first case) or get null (in the second case).

    Now, let's look at your specific situation, and relate it.  You have the following:

    class ItemList : List<Item>
    {
    }
    
    

    When you run, you're creating a List<Item> here:

    List<Item> temporaryCreatedInline = items.Where(x => x.ItemType != ItemType.Car).ToList();
    However, you're trying to set this temporary variable to an ItemList class reference:

    ItemList list = temporaryCreatedInline; // Compiler failure!
    This is the same as if you did the following above:

    Cat cat = new Mammal(); // Fails!
    (ItemList == Cat and List<Item> == Mammal).

    Even if you put a cast in there, it doesn't change the fact that List<Item> is not actually an ItemList  - so you can't just directly cast this.  ItemList is a List<Item>, (just as Cat is a Mammal), but the opposite is not true.

    This, I agree, can be frustrating.  However, the core issue is that the CLR and the compiler cannot do what you are trying to do.  In your case, technically, an ItemList is basically equivelent to List<Item> (since you add no new fields, members, etc), but technically, it is not the same thing.  It would be a violation of basic object oriented principles in a strongly typed language to allow the cast to go through, since it would mean List<Item> would have to actually become an ItemList - even though it wasn't constructed as one.

    Granted, in dynamically typed languages that support some form of duck typing, this would work.  C#, however, is not a dynamically typed language - it is a fully static typed language, and does not allow this to go through.

    In your case, I recommended adding a new constructor to ItemList that took an IEnumerable<Item>.  This would let you create an ItemList from the LINQ statement, but you'd be creating a new instance of an ItemList class. 


    Reed Copsey, Jr. - http://reedcopsey.com
    • Marked as answer by NoEgo Friday, December 11, 2009 7:45 PM
    Friday, December 11, 2009 6:52 PM
    Moderator
  • Reed, I understand and really appreciate your time.  You've really helped clear this up for me as far as the is A related to variable use.
    C# Web Developer
    Friday, December 11, 2009 7:44 PM