IEnumerable<T> assignment - c#

I have two objects declared as IEnumerable<DateTime> xVal and IEnumerable<double> yVal.
Then some where is my program I have:
var xVals = from p in result where p.chemical == "Benzene" select p.SampDate_Name;
var yVals = from p in result where p.chemical == "Benzene" select p.PCL;
Then I am trying to the following assignment:
xVal = xVals as IEnumerable<DateTime>;
yVal = yVals as IEnumerable<double>;
And the above code sets xVal and yVal to null.
Could anybody explain what is wrong here? I would very much appreciate the help.
Thanks.
One thing is certain: The input is not null. So xVals and yVals are non-null as debugged by me. I am also able to loop through them to get the content of each.
I will try the other suggestions when I get back and post my findings. Thanks a lot folks for your replies.
The problem here was that LINQ is executed lazy, It will be executed when you do either foreach or ToList/ToArray/ToDictionary. The two linq queries in my code were not executed before the assignment was done. Consequently xVal and yVal were set to null.
Thanks for all the help.

The as keyword will set the output to null if the input was null or the cast could not be carried out.
If you used xVal = (IEnumerable<DateTime>)xVals you would probably get an exception saying that it could not be cast.
MSDN description for as keyword

If you have a generic collection, to get it to IEnumerable, try .AsEnumerable(). So your new code...
xVal = xVals.AsEnumerable();
yVal = yVals.AsEnumerable();

The as keyword doesn't actually do a cast, but does conversions between related reference types. So if you have a concrete type, you could treat assign it to a new variable with a type of the base class using as. If the types are not compatible, then as will return null. This is a good way to do type checking without having to worry about exceptions. Instead you can perform a null check on the result of the conversion.
It's hard to tell what types p.SampDate_Name and p.PCL are, but I would guess strings? If so you can add the cast to the select statement.
var xVals = from p in result where p.chemical == "Benzene" select DateTime.Parse(p.SampDate_Name);
var yVals = from p in result where p.chemical == "Benzene" select Double.Parse(p.PCL);

Related

DataTable Linq with two join statements in C#

My code:
var Result = from TempRow in ArrAbsDiff
where TempRow.Strike == StrikeOfMinAbsDiff
select TempRow.PutMidPrice;
I know that the above code return just one value of type decimal (maybe double). However, Result is of type Enumerable and I could not easily write Result + 2. I need to convert it property. I can do it through the following code:
var Result = (from TempRow in ArrAbsDiff
where TempRow.Strike == StrikeOfMinAbsDiff
select TempRow.PutMidPrice).Min();
Is there more efficient way to accomplish it?
Regards,
I know that the above code return just one value of type decimal
Then use First method instaed of Min.
At compile time, it's unknown whether the query you have returns 1 record or more than 1 record. So, it assumes a list of them.
I don't know if there is a performance difference between them, I typically use .Single() to get the single record. It's more clear that I want a single record and not, for example, the minimum one.
Try using FirstOrDefault()" this selects the first result returned (as you know only one value will be returned). if a value is not returned the Result will be null, catch this in an if statement like below:
var Result = (from TempRow in ArrAbsDiff
where TempRow.Strike == StrikeOfMinAbsDiff
select TempRow.PutMidPrice).FirstOrDefault();
if (Result == null)
return; // or error message
this will also keep the type of value returned
(typed this of the top of my head, may need slight changes!)

Linq - Distinct list of object fill in int array

I am trying to do, get randomly one of "list of objects" from all lists.
I am getting NullReferenceException I also tried List couldn't make it work.
List<BL.Test.Test> Tests = BL.Test.GET.TestGroup(CategoryId);
// NullReferenceException on the line below:
int[] Groups = Tests.Select(d => d.TestGroupId).Distinct().ToArray();
Session["TestGroup"] = Tests.Select(t => t.TestGroupId = Groups[rnd.Next(Groups.Length)]);
Obviously, BL.Test.GET.TestGroup is the method which returns null.
That's the most probable explanation for a NullReferenceException in a second line of your example.
And if Select, Distinct and ToArray are extension methods declared in System.Linq, this reason is the only possible, so check your method.
UPD.
Sorry guys, I am wrong.
TestGroupId member of BL.Test.Test class is missed.
UPD-2
This is a good example of community debugging question. As I know it is not appreciated here
Since TestGroupId would be null hence null.Distinct() throws NullArgumentReference exception.
Change ur code with following code:
List<BL.Test.Test> Tests = BL.Test.GET.TestGroup(CategoryId);
int[] Groups = Tests.Where(d=>d.TestGroupId.HasValue).Select(d => d.TestGroupId).Distinct().ToArray();
Session["TestGroup"] = Tests.Select(t => t.TestGroupId = Groups[rnd.Next(Groups.Length)]);
Make use of HasValue to find if TestGroupId has some value.

LINQ query help please, for each works?

I have a problem with some code that simply can’t work in LINQ, but it does work as a simple for..each. Any explanation and solution would be appreciated.
I have 3 classes, Users, User , UserPermissions composed as follows:
Class Users
ObservableCollection<User> GetList
Class User
Public int id {get;set;}
Public string UserName {get;set;}
Public UserPermissions Permissions {get;set;}
Class UserPermissions
Public Int ID {get;set;}
Public int ApplicationID {get;set;}
This works and returns the correct user:
Users users = new Users();
foreach (User u in users.GetList() )
{
if (u.UserName==username && u.Permissions.ApplicationID == applicationId)
{
usr = u;
break;
}
}
The linq below 'should' do the same thing, but it doesn’t. There are no errors returned or raised in the output window, and the musers variable simply doesn't exist after stepping over it. I have tried being more specific in my casts and using AsQueryable. I even tried let p=u.Permissions, using two from commands, but nothing seems to fix it.
My worry is that my other classes will suffer from this and cause issues later on as more complex queries are used.
var musers = from Users.User u in UsersList
where (u.UserName==userName)
&& (u.Permissions.ApplicationID == ApplicationId)
select u.ID;
One more bit of information the following errors too?
var t1 = UsersList.SelectMany( u => u.Permissions);
Error 1 The type arguments for method 'System.Linq.Enumerable.SelectMany(System.Collections.Generic.IEnumerable, System.Func>)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
var usr = users.GetList()
.FirstOrDefault(
p => p.UserName == username
&& p.Permissions.ApplicationID == applicationId);
Should actually do it for you. FirstOrDefault can return null, if no user has been found...
Adam was spot on thank you Adam.
I have seen in the debugger that 'var found=from...' showed that found is created and contains a value at the point where the linq statement is run. However, as Adam correctly states that linq enumeration is deferred until the point you enumerate the query. The reason it all looked fine to me was that directly under the code that worked was a for loop which triggers the enumeration for THAT linq query. The others above it had no such enumeration so just looked as if they had failed silently!
I think the compiler was optimizing the function so that I could debug the linq query at the point it is in the code rather than where the enumeration occurs, nice trick but it completely wrong footed me! lol. It made me think that the query itself is evaluated to some degree even if the results aren't available until you use ToList(), Count() or other enumeration function.
for example in the code below only f3 will contain anything at all, the others are just, well, nothing because they are never enumerated!
var f1 = from .....;
var f2 = from ....;
var f3 = from ....;
do lots of other stuff, even call a function
int count = f3.Count();
What is interesting is that f1, f2 are nothing even after the line runs but f3 has a value immediately after and before the enumeration (Count) takes place, so i think compiler optimization/debug is playing a part here.
Hope this helps someone else :)

LINQ to returns count even the list is empty

I have this block of code inside another LINQ statement.
VideoLinks = (from video in m.VideoLinks.DefaultIfEmpty(new VideoGallery())
orderby video.CreatedDate
select new VideoGallery()
{
Source = video.Source,
Type = video.Type,
Links = video.Links,
Title = video.Title
}).ToList()
unfortunately if dont use DefaultIfEmpty its through me an exception. If I use DefaultIfEmpty i give count as 1 for videolinks even if m.VideoLinks is null.
So now how can avoid getting count 1 if m.VideoLinks is null
DefaultIfEmpty is going to give you a default value. It counts as an item when you call ToList() on it...thus your count is 1.
This looks like you are using linq-to-objects, so you should add a where video != null
VideoLinks = (from video in m.VideoLinks
where video != null
orderby video.CreatedDate
select new VideoGallery()
{
Source = video.Source,
Type = video.Type,
Links = video.Links,
Title = video.Title
}).ToList()
wllmsaccnt is correct - your problem is the "DefaultIfEmpty" portion of your statement. By definition, you are requesting that there be at least one item in the collection, according to the definition of this method:
Returns the elements of the specified sequence or the specified value
in a singleton collection if the sequence is empty
I think the important question here is what exception are you receiving when you don't use DefaultIfEmpty? If you tell us that, perhaps we can help you avoid it...

Basic LinqToSql question: Why won't this compile?

I've been introducing myself to LinqToSQL lately through a poorly-made project at work. I'm curious as to why this works:
var territories = db.Territories.Where(t => t.PendingUserCount > 0);
But this results in a compilation error:
var territories = db.Territories;
if (someCondition)
territories = territories.Where(t => t.PendingUserCount > 0);
// Cannot implicitly convert 'System.Linq.IQueryable<Territory> to System.Data.Linq.Table<Territory>
I've also tried to call db.Territories.ToList(), but to no avail.
I'm sure it's just a misunderstanding of how Linq works, but I'd be appreciative if someone could help me out.
db.Territories returns a table object. Hence the 'var' will be of type System.Data.Linq.Table. Later you try (based on some condition) to assign something of type System.Linq.IQueryable to the variable. As .NET is strongly typed, the compiler throws an error.
Variables of type var will be assigned a type when they get assigned first. That's how I try to remember myself.
For this type of cumulative Where, you need to tell the compiler to use IQueryable<T>:
IQueryable<Territory> territories = db.Territories;
if (someCondition)
territories = territories.Where(t => t.PendingUserCount > 0);
... etc
Alternative:
var territories = db.Territories.AsQueryable();
if (someCondition)
territories = territories.Where(t => t.PendingUserCount > 0);
change to this
var territories = db.Territories;
to
IQueryable territories = db.Territories.Where(t => t.PendingUserCount > 0);
The reasoning is that by calling db.Territories, you are getting all the data back, returning it in a linq.table object. Db.Territores.where(... will return an IQueryable object instead.
One of the potentially confusing things about "var" is that its type is determined at compile time, so you can't assign a range of different types to it. People with experience of dynamic languages, like Python, sometimes get confused by this, at first.
Your var territories is typed as a System.Data.Linq.Table<Territory> initially and then you are trying to assign the results of a Where clause (which is of type System.Linq.IQueryable<Territory>) to it.
Remember that the compiler infers the type of a var at assignment so once it is assigned the type cannot be changed.
Try something like this:
System.Linq.IQueryable<Territory> territories;
if (someCondition)
territories = db.Territories.Where(t => t.PendingUserCount > 0);
Because you've typed "var" as a Table<Territory> and then try to reassign it as a IQueryable<Territory>.
This is equivalent to saying
var i = 0
i = "a string";
EDIT: To clarify, var is implicitly strong typed at compile time not run time, unlike dynamically typed scripting language.
You can't re-assign a var to a different type after you've declared it. So your var declaration has already typed it to System.Data.Linq.Table.
It's a fire once thing.
You need to use the IQueryable tyupe as others have suggested:
also this linq query maybe also work:
var query = from territories in db.Territories
where territories.SomeProperty == SomeCondition
where territories.PendingUserCount > 0
select territories;

Categories

Resources