How to use multiple lines in .OrderBy in c#? - c#

I have this code
folderList = (List<SPFolder>)folderList.OrderBy(folder => Object x = folder.GetProperty("Order Folder By"); x == null ? 0 : (int)x;).ToList();
But it's giving me a syntax error.
Does anyone know whats wrong here?
Thanks.

You're not returning anything. You need to return the value in a statement lambda. You also need to wrap the statements in curly braces to use multiple statements in a lambda. You also can't treat a conditional operator as an expression; it needs to be a statement.
They're fixed with the same fix.
folderList = (List<SPFolder>)folderList.OrderBy(folder => {
Object x = folder.GetProperty("OrderFolderBy");
return x == null ? 0 : x;}).ToList();
That said, you can do the whole thing with just an expression instead; there's no need to use multiple statements:
folderList = folderList.OrderBy(folder => folder.GetProperty("OrderFolderBy") as int?).ToList();
There also no reason for that cast. The list should already be of the appropriate type, and both null and 0 come before other numbers, so there's no real reason for the null check at all.

You need the braces since you had two statements in the lambda and you also need the cast to object for the ? : operator
folderList = folderList.OrderBy(
folder =>
{
Object x = folder.GetProperty("OrderFolderBy");
return x == null ? (object)0 : x;
}).Cast<SPFolder>().ToList();

You can avoid using the intermediate assignment to x by using the null coalescing operator ??.
folderList = folderList.OrderBy(
folder => folder.GetProperty("OrderFolderBy") ?? (object)0)
.ToList();

Related

Using "And" operator comparing three variables

if (dr["programmeCode"].ToString() == (combo_Programme.ToString())) &= (dr["Actions_ProgrammeDerivedCode"].ToString()) = null;
Can anyone help and explain why my "And" expression "&=" (or "&&") will not work in the above expression ?
you cand do the following..
if (dr["programmeCode"].ToString() == combo_Programme.ToString()
&& string.IsNullOrEmpty(dr["Actions_ProgrammeDerivedCode"].ToString()))
{
}
I am not sure what you are trying to do and neither is the computer. I am assuming your code is all part of the logical statement.
The &= assigns a value to the variable on the left of it. So in your case, you would be trying to assign (dr["Actions_ProgrammeDerivedCode"].ToString() to the if statement!
You meant to use the && operator, then you might note that your parentheses exclude the statement from the logical test. You need to add more parentheses and change the = null to == null or it will also try to assign:
if ((dr["programmeCode"].ToString() == combo_Programme.ToString())
&& (dr["Actions_ProgrammeDerivedCode"].ToString() == null)) {
do something...
}
Here is a link to some helpful documentation on variable assignment:
https://msdn.microsoft.com/en-us/library/e669ax02.aspx
Here is a link to some helpful documentation on if statements:
https://msdn.microsoft.com/en-us/library/5011f09h.aspx

How can I use the conditional null operator to check for null string?

I'm trying to execute the LINQ to objects query as follows:
var c1 = allCustomers
.Where(x => x.CompanyName.Replace("'", "").StartsWith(searchText))
.ToList();
This works fine as long as CompanyName is not null.
So, I thought this seems like the perfect place for the new null conditional operator! Just change to:
var c1 = allCustomers
.Where(x => x.CompanyName?.Replace("'", "").StartsWith(searchText))
.ToList();
and everything should work!
Instead, I get the error:
Cannot implicitly convert type 'bool?' to 'bool'. An explicit conversion exists (are you missing a cast?)
I'm not quite sure how to accomplish what I want here. How would I use the null conditional in this scenario?
You need a coalesce operator to convert the tri-state to a proper boolean.
var c1 = allCustomers
.Where(x => x.CompanyName?.Replace("'", "").StartsWith(searchText) ?? false)
.ToList();
I call bool? a tri-state because it can have three values: true, false and null; therefore, converting bool? to bool is a narrowing conversion that requires explicit treatment.
you need more question marks! i think you need null coalescing as well, since x.CompanyName?.Replace could now also return null.
(x.CompanyName?.Replace("'", "") ?? string.Empty).StartsWith(searchText))
the ?? string.empty forces that to be a non-null string, which now supports .startswith
Use ?? operator like:
Where(x => x.CompanyName?.Replace("'", "").StartsWith(searchText) ?? false)

LINQ - FirstOrDefault() then Select()

I have the following LINQ query that fires an exception when the FirstOrDefault() returns null. Ideally I would like to avoid the null check. Is there a way to do this? I wish to return 0 if there are no CPOffsets that satisfy the FirstOrDefault() call.
double offset = OrderedOffsets.FirstOrDefault(o => o.OffsetDateTime > cpTime).CPOffset;
The only way I can see to achieve this is the following:
CPOffset cpOffset = OrderedOffsets.FirstOrDefault(o => o.OffsetDateTime > cpTime);
double offset = cpOffset != null ? cpOffset.CPOffset : 0;
Is there another more succinct way? Using Select() after the FirstOrDefault() doesn't compile but I thought might be appropriate here?
I think this should work, I'm not near by VS to check it out...
OrderedOffsets.Where(o => o.OffsetDateTime > cpTime).Select(x => x.CPOffset).FirstOrDefault();
DefaultIfEmpty can be used to ensure that the collection always has at least one element.
double offset = OrderedOffsets.Where(o => o.OffsetDateTime > cpTime)
.Select(o => o.CPOffset)
.DefaultIfEmpty()
.First();
I think a good pattern could be :
double offset = (OrderedOffsets.FirstOrDefault(o => o.OffsetDateTime > cpTime) ?? someDefaultObject).CPOffset;
with someDefaultObject an object holding default values... With this pattern, you can change easily you default values through your code !
If OrderedOffsets can be a struct you could also just put your default value there ! :)

How to get the Null Coalesce operator to work in ASP.NET MVC Razor?

I have the following, but it's failing with a NullReferenceException:
<td>#item.FundPerformance.Where(xx => fund.Id == xx.Id).FirstOrDefault().OneMonth ?? -</td>
OneMonth is defined as
public virtual decimal? OneMonth { get; set; }
and its value is null at the time that it fails.
I thought the Null Coalesce operator would test if its null and if so, return the value to the right of the operator?
What do I need to change to make this work?
The razor syntax, as you wrote it, ends at "OneMonth". The ?? are interpreted as text. To have it interpreted as razor, you must wrap the whole statements in () like this:
<td>#(item.FundPerformance.Where(xx => fund.Id == xx.Id).FirstOrDefault().OneMonth ?? "-")</td>
This will still get you an error: the left operator is a decimal and the right operator is a string. So you can either render a zero instead of "-" or use ternary operator, with OneMonth.Value.ToString() as left value and "-" as right value.
It's nothing to do with MVC or Razor.
FundPerformance.Where(xx => fund.Id == xx.Id).FirstOrDefault()
will return null if there is no element that matches, null does not have a OneMonth porperty so you will get a null ref exception. You cannot use the ?? operator as it is not OneMonth that is null, it is the result of FirstOrDefault().
To test change your code to
FundPerformance.Where(xx => fund.Id == xx.Id).First().OneMonth ?? -</td>
If you get a "sequence contains no elements" exception instead then you know that is your problem.

Are ternary operators not valid for linq-to-sql queries?

I am trying to display a nullable date time in my JSON response. In my MVC Controller I am running the following query:
var requests =
(from r in _context.TestRequests
where r.scheduled_time == null && r.TestRequestRuns.Count > 0
select new
{
id = r.id,
name = r.name,
start = DateAndTimeDisplayString(r.TestRequestRuns.First().start_dt),
end = r.TestRequestRuns.First().end_dt.HasValue
? DateAndTimeDisplayString(r.TestRequestRuns.First().end_dt.Value)
: string.Empty
});
When I run requests.ToArray() I get the following exception:
Could not translate expression '
Table(TestRequest)
.Where(r =>
((r.scheduled_time == null) AndAlso (r.TestRequestRuns.Count > 0)))
.Select(r => new <>f__AnonymousType18`4(id = r.id, name = r.name,
start = value(QAWebTools.Controllers.TestRequestsController).
DateAndTimeDisplayString(r.TestRequestRuns.First().start_dt),
end = IIF(r.TestRequestRuns.First().end_dt.HasValue,
value(QAWebTools.Controllers.TestRequestsController).
DateAndTimeDisplayString(r.TestRequestRuns.First().end_dt.Value),
Invoke(value(System.Func`1[System.String])))))'
into SQL and could not treat it as a local expression.
If I comment out the end = line, everything seems to run correctly, so it doesn't seem to be the use of my local DateAndTimeDisplayString method, so the only thing I can think of is Linq to Sql doesn't like Ternary operators? I think I've used ternary operators before, but I can't remember if I did it in this code base or another code base (that uses EF4 instead of L2S).
Is this true, or am I missing some other issue?
Modify the DateAndTimeDisplayString to accept a different argument type and have a query like this:
end = DateAndTimeDisplayString(r.TestRequestRuns.FirstOrDefault())
This way, you can do the ternary stuff in your code.
By the way, it's actually this part which looks bad, because the ternary gets translated to IIF and seems to be handled, maybe try a null string:
Invoke(value(System.Func`1[System.String])))))
Have you considered using the Null coalescing operationg? (??)
Your code would then look like this:
end = r.TestRequestRuns.First().end_dt ?? string.Empty
You could modify your DateAndTimeDisplayString method to return null if passed null.

Categories