Reputation: 13626
Why IntelliSense dosen't give me option to select properties of the Glasses collection(i.e itemToDelete) after implimenting the LINQ.
Here is my C# LINQ:
public static void DeletePicturesFromHrdDisc(List<Glasses> Temp, int GlassID)
{
var itemToDelete = (from item in Temp
where item.GlassesID==GlassID
select item);
itemToDelete.(dosen't give me the optipn to select Properties of the Glasses class)
}
here is my Glasses class:
public class Glasses
{
public string Brand { get; set; }
public string SmalPicture { get; set; }
public string BigPicture { get; set; }
public string color { get; set; }
public string FrameType { get; set; }
public int GlassesID { get; set; }
public string NameGlasses { get; set; }
public string Collection { get; set; }
}
But I can see Glasses properties if i use .First() or .FirstorDefault() extensions as follows:
Any idea why can't I access the properties in the first version and why i see them in IntelliSense only if i use .First() or .FirstorDefault() extensions on my LINQ.
Thank you in advance!
Upvotes: 3
Views: 1027
Reputation: 69270
LINQ queries always produce a seqence of items, of type IEnumerable<Glasses>
in your case. Even if there is only one element in the sequence, it is still a sequence. The sequence itself can only be enumerated, it does not have any other properties. To get at the elements' properties you first have to extract an element. That's exactly what First()
does. It returns the first element of the sequence.
If your query always should produce exactly one item and any other result is an error you should use Single()
instead of First()
. If zero or one elements are acceptable you can use SingleOrDefault()
and check the result for null
.
Upvotes: 3
Reputation: 1777
BTW, you can hover over var
in Visual Studio to see the type of an expression.
In this case, itemToDelete
is an IEnumerable<Glasses>
of Glasses
in Temp
with a GlassesID
of GlassID
. Assuming your GlassesID
is actually unique in Temp
, it will only have one item which you can extract with .Single()
or .SingleOrDefault()
.
EDIT: As others have pointed out, .Single()
, not .First()
is the right method to use if you want to check for exactly one item.
Upvotes: 5
Reputation: 15861
as the first() will give only a single item. so the compiler is giving intellisense for it. as the 1st version is IEnumerable<Glasses>
so it has collection of objects. you need to iterate it.
var itemToDelete = (from item in Temp
where item.GlassesID==GlassID
select item);
foreach(var i in itemToDelete )
{
i.SomeProperty // do some thing with i ;
}
Upvotes: 1
Reputation: 180987
When you apply Where/Select to Temp, you're not just getting a single result (there could be more than one result matching where item.GlassesID==GlassID
, the compiler cannot be sure) so it does not return a single object instance of Glasses but an IEnumerable<Glasses>. Simplified, think that you get a List<Glasses> back and you need to extract the actual object from the List before using its properties.
If you definitely know there's at most only one result returned, you can use SingleOrDefault()
which returns the Glasses instance in the IEnumerable or null if it's empty, or Single()
which returns the Glasses instance in the IEnumerable and throws an error if there isn't one. Both throw an exception if there is more than one result.
Using First()
or FirstOrDefault()
would mean that if you accidentally get more than one result, you'll in this case get the first one, a random one. Perhaps not a good thing for an "itemToDelete", you'd probably want to know if your assumption is wrong.
Upvotes: 5
Reputation: 93444
Because your first version is a collection of Glasses, not a Glasses object itself. First()
or FirstOrDefault()
return a single instance of Glasses, thus the properties are available.
Upvotes: 2