C# short-circuiting weirdness - c#

Given a = null
Shouldn't this not throw an exception?
if(a != null && ((string)a).ToLower()=="boo"){
... operation
}
Due to lazy evaluation the second statement should never be called so this ((string)a).ToLower() shouldn't be throwing an exception right ?
UPDATE
IOrderedEnumerable<SPListItem> Items = sourceList.GetItems("ProjectID", "Title", "ProjectName", "Featured", "Size", "Description")
.Cast<SPListItem>().AsEnumerable().OrderBy((i => rnd.Next()));
SPListItemCollection randProjImages = SPContext.Current.Web.Lists.TryGetList("Random Projects Images").GetItems();
var randomImgNrs = Enumerable.Range(0, randProjImages.Count).OrderBy(i => rnd.Next()).ToArray();
Dictionary<string, string> projectImages = new Dictionary<string,string>();
IEnumerable<SPListItem> projImages = SPContext.Current.Web.Lists.TryGetList("Assigned Projects Images").
GetItems().Cast<SPListItem>().AsEnumerable();
foreach (SPListItem it in projImages) projectImages.Add((string)it["ProjectID"], (string)it["ServerUrl"]);
int qCount = 0;
foreach (SPListItem item in Items) {
if (item["Size"] != null && item["Featured"]!=null &&
((string)item["Size"]).ToLower() == "big" || ((string)item["Featured"]).ToLower() == "yes") {
dataItems.Add(new Project(item["ProjectID"].ToString(), (string)item["Title"],
"/sites/Galileo/SitePages/" + Utils.getCurrentLang().ToLower() + "/Projects.aspx#id=pwp" + item["ProjectID"],
projectImages[(string)item["ProjectID"]],
Utils.truncateString(item.Fields["Description"].GetFieldValueAsText(item["Description"]), 175), "project"));
}else{
Replacing the foreach with this:
foreach (SPListItem item in Items) {
var k = item["Size"];
if (item["Size"] != null && item["Featured"]!=null &&
((string)item["Size"]).ToLower() == "big" || ((string)item["Featured"]).ToLower() == "yes") {
dataItems.Add(new Project(item["ProjectID"].ToString(), (string)item["Title"],
"/sites/Galileo/SitePages/" + Utils.getCurrentLang().ToLower() + "/Projects.aspx#id=pwp" + item["ProjectID"],
projectImages[(string)item["ProjectID"]],
Utils.truncateString(item.Fields["Description"].GetFieldValueAsText(item["Description"]), 175), "project"));
}else{
And breaking just before the if statement in the debugger, k == null

if (item["Size"] != null && item["Featured"]!=null &&
((string)item["Size"]).ToLower() == "big" || ((string)item["Featured"]).ToLower() == "yes")
it goes to the ((string)item["Featured"]).ToLower() == "yes")

No exception:
string a = null;
if (a != null && ((string) a).ToLower() == "boo")
string a = "";
if (a != null && ((string) a).ToLower() == "boo")
string a = "boo";
if (a != null && ((string) a).ToLower() == "boo")
this is as it should be (though the casting is unnecessary).
Does not compile:
T a = new T();
if (a != null && ((string) a).ToLower() == "boo")
T? a = null;
if (a != null && ((string) a).ToLower() == "boo")
T? a = new T();
if (a != null && ((string) a).ToLower() == "boo")
where T is any type other than string due to casting from T to string.
The real question is: Why do think it throws an exception?

Use
String.IsNullOrWhiteSpace(a)

You are right that the second argument of && is not evaluated if the first argument is false (a is null). So the code cannot throw a NullReferenceException. However, if a is not null but an object that cannot be cast to string, the code can throw an InvalidCastException.
Note that the best practice for comparing strings in a case-insensitive way is to use the String.Equals Method:
if (String.Equals(a, "foo", StringComparison.CurrentCultureIgnoreCase))
{
// ... operation
}
Since the method is static, no null-check is needed.

Exactly, this will not throw an exception. Since your expression is AND, evaluating only the first part is enough to know that it will never evaluate to true, so the second part is skipped.

Correct! (except that it's not called lazy evaluation)
If the first operand evaluates to true, the second operand isn't evaluated.
http://msdn.microsoft.com/en-us/library/vstudio/6373h346.aspx

Related

convert lambda expression to function

I wish to debug lambda expression but its not possible as it sets breakpoint on whole expression.
Here is my lambda expression
public bool CanRevert => _objectEntity != null && !(_objectEntity != null &&
ObjectDescription == _objectEntity.DTO.Description &&
ObjectInstance == _objectEntity.DTO.ObjectInstance.ToString() &&
Name == _objectEntity.DTO.ObjectName &&
(SelectedDevice != null && SelectedDevice.Id == _objectEntity.DTO.DeviceID) &&
(_objectEntity.DTO.ObjectCategoryID.HasValue ? (SelectedObjectCategory != null && SelectedObjectCategory.Id == _objectEntity.DTO.ObjectCategoryID.Value) : SelectedObjectCategory == null) &&
(_objectEntity.DTO.ObjectTypeID.HasValue ? (SelectedObjectType != null && SelectedObjectType.Id == _objectEntity.DTO.ObjectTypeID.Value) : SelectedObjectType == null));
I wanted to put breakpoint inside selectedDevice but i cant. Hence i tried to write it like
public bool CanRevert()
{
if (SelectedDevice != null)
{
var s = SelectedDevice.Id == _objectEntity.DTO.DeviceID;
}
var d = _objectEntity != null && !(_objectEntity != null &&
ObjectDescription == _objectEntity.DTO.Description &&
ObjectInstance == _objectEntity.DTO.ObjectInstance.ToString() &&
Name == _objectEntity.DTO.ObjectName &&
(SelectedDevice != null && SelectedDevice.Id == _objectEntity.DTO.DeviceID) &&
(_objectEntity.DTO.ObjectCategoryID.HasValue ? (SelectedObjectCategory != null && SelectedObjectCategory.Id == _objectEntity.DTO.ObjectCategoryID.Value) : SelectedObjectCategory == null) &&
(_objectEntity.DTO.ObjectTypeID.HasValue ? (SelectedObjectType != null && SelectedObjectType.Id == _objectEntity.DTO.ObjectTypeID.Value) : SelectedObjectType == null));
return d;
}
Is it right way to convert it? I ask because i am starting to get somewhere in application that Binding to this method is not supported
You can achieve the same result like this.
Put a breakpoint in your expression.
Start Debugging (F5)
Highlight (SelectedDevice != null && SelectedDevice.Id == _objectEntity.DTO.DeviceID) in your expression
Right-click and select Add Watch
Now you have its calculated value in the Watch window. (Usually pops up at the bottom)
You can use Quick Watch (Shift+F9) if you want its value once.

How to handle NULL when using String.StartsWith method

How do I handle a null when using the String.StartsWith() in a complex where clause ?
var value = _context.Repo.Pages.Where(r => r.Sdate <= data.Pdate && (r.Edata == null || data.RData <= r.Edata)
&& ......
&& ...... several conditions
&& ......
|| (data.SisPlan.StartsWith("T") && r.SisN == data.SisCal));
I've tried data?.SisPlan.StartsWith("T") but get the message:
Operator '&&' cannot be applied to opperands of type 'bool?' and
'bool'
I'm trying to prevent doing a null check outside of the where clause.
The usual way is to write:
|| ((data?.SisPlan?.StartsWith("T") ?? false) && r.SisN == data.SisCal));
We rely on the ?? operator to get the null case and in this case we return a false value. The ?? is called the null coalescing operator.
Basically,
var a = data?.SisPlan?.StartsWith('T') ?? false;
is a syntaxic sugar for
bool a = false;
if (data != null && data.SisPlan != null && data.SisPlan.StartsWith('T'))
a = true;

How can I pull a repeated where clause expression from linq into a function?

I have a large project where I have dozens of linq statements where I am looking for a matching record by checking several fields to see if they match or both field and compared field are null.
var testRecord = new { firstField = "bob", secondField = (string)null, thirdField = "ross" };
var matchRecord = dataContext.RecordsTable.FirstOrDefault(vi =>
(vi.first == testRecord.firstField || ((vi.first == null || vi.first == string.Empty) && testRecord.firstField == null))
&& (vi.second == testRecord.secondField || ((vi.second == null || vi.second == string.Empty) && testRecord.secondField == null))
&& (vi.third == testRecord.thirdField || ((vi.third == null || vi.third == string.Empty) && testRecord.thirdField == null)));
//do stuff with matchRecord
Ideally I would replace all that duplicated code (used around 50 times across the system I'm working on) with something like the following
Expression<Func<string, string, bool>> MatchesOrBothNull = (infoItem, matchItem) => (
infoItem == matchItem || ((infoItem == null || infoItem == string.Empty) && matchItem == null));
var matchRecord = dataContext.RecordsTable.FirstOrDefault(vi =>
MatchesOrBothNull(vi.first, testRecord.firstField)
&& MatchesOrBothNull(vi.second, testRecord.secondField)
&& MatchesOrBothNull(vi.third, testRecord.thirdField));
//do stuff with matchRecord
My question is two-fold: First, is there a matched or both null function already available? (I've looked without luck).
Second, the code block above compiles, but throws a "no supported translation to sql" error, is there a way to have a function in the where clause? I know that there is a translation because it works if I don't pull it into the function. How can I get that translated?
First of all you can check whether string is null or empty with single code which is called : String.IsNullOrEmpty(vi.first). You need a method like this one :
public bool MatchesOrBothNull(string first,string second){
if(first==second||String.IsNullOrEmpty(first)||String.IsNullOrEmpty(second))
return true;
else return false;
}
You can use it in where clause
var matchRecord = dataContext.RecordsTable.Where(vi =>
MatchesOrBothNull(vi.first, testRecord.firstField)
&& MatchesOrBothNull(vi.second, testRecord.secondField)
&& MatchesOrBothNull(vi.third, testRecord.thirdField)
).FirstOrDefault();

Entity Framework: Count() very slow on large DbSet and complex WHERE clause

I need to perform a count operation on this Entity Framework (EF6) data set using a relatively complex expression as a WHERE clause and expecting it to return about 100k records.
The count operation is obviously where records are materialized and therefore the slowest of operations to take place. The count operation is taking about 10 seconds in our production environment which is unacceptable.
Note that the operation is performed on the DbSet directly (db being the Context class), so no lazy loading should be taking place.
How can I further optimize this query in order to speed up the process?
The main use case is displaying an index page with multiple filter criteria but the the function is also used for writing generic queries to the ParcelOrderstable as required for other operations in the service classes which might be a bad idea resulting in very complex queries resulting from laziness and might potentially be a future problem.
The count is later used for pagination, and a much smaller number of records (e.g. 500) is actually displayed. This is a database-first project using SQL Server.
ParcelOrderSearchModel is a C#-class that serves to encapsualte query parameters and is used exclusively by service classes in order to call the GetMatchingOrdersfunction.
Note that on the majority of calls, the majority of the parameters of ParcelOrderSearchModel will be null.
public List<ParcelOrderDto> GetMatchingOrders(ParcelOrderSearchModel searchModel)
{
// cryptic id known --> allow public access without login
if (String.IsNullOrEmpty(searchModel.KeyApplicationUserId) && searchModel.ExactKey_CrypticID == null)
throw new UnableToCheckPrivilegesException();
Func<ParcelOrder, bool> userPrivilegeValidation = (x => false);
if (searchModel.ExactKey_CrypticID != null)
{
userPrivilegeValidation = (x => true);
}
else if (searchModel.KeyApplicationUserId != null)
userPrivilegeValidation = privilegeService.UserPrivilegeValdationExpression(searchModel.KeyApplicationUserId);
var criteriaMatchValidation = CriteriaMatchValidationExpression(searchModel);
var parcelOrdersWithNoteHistoryPoints = db.HistoryPoint.Where(hp => hp.Type == (int)HistoryPointType.Note)
.Select(hp => hp.ParcelOrderID)
.Distinct();
Func<ParcelOrder, bool> completeExpression = order => userPrivilegeValidation(order) && criteriaMatchValidation(order);
searchModel.PaginationTotalCount = db.ParcelOrder.Count(completeExpression);
// todo: use this count for pagination
}
public Func<ParcelOrder, bool> CriteriaMatchValidationExpression(ParcelOrderSearchModel searchModel)
{
Func<ParcelOrder, bool> expression =
po => po.ID == 1;
expression =
po =>
(searchModel.KeyUploadID == null || po.UploadID == searchModel.KeyUploadID)
&& (searchModel.KeyCustomerID == null || po.CustomerID == searchModel.KeyCustomerID)
&& (searchModel.KeyContainingVendorProvidedId == null || (po.VendorProvidedID != null && searchModel.KeyContainingVendorProvidedId.Contains(po.VendorProvidedID)))
&& (searchModel.ExactKeyReferenceNumber == null || (po.CustomerID + "-" + po.ReferenceNumber) == searchModel.ExactKeyReferenceNumber)
&& (searchModel.ExactKey_CrypticID == null || po.CrypticID == searchModel.ExactKey_CrypticID)
&& (searchModel.ContainsKey_ReferenceNumber == null || (po.CustomerID + "-" + po.ReferenceNumber).Contains(searchModel.ContainsKey_ReferenceNumber))
&& (searchModel.OrKey_Referencenumber_ConsignmentID == null ||
((po.CustomerID + "-" + po.ReferenceNumber).Contains(searchModel.OrKey_Referencenumber_ConsignmentID)
|| (po.VendorProvidedID != null && po.VendorProvidedID.Contains(searchModel.OrKey_Referencenumber_ConsignmentID))))
&& (searchModel.KeyClientName == null || po.Parcel.Name.ToUpper().Contains(searchModel.KeyClientName.ToUpper()))
&& (searchModel.KeyCountries == null || searchModel.KeyCountries.Contains(po.Parcel.City.Country))
&& (searchModel.KeyOrderStates == null || searchModel.KeyOrderStates.Contains(po.State.Value))
&& (searchModel.KeyFromDateRegisteredToOTS == null || po.DateRegisteredToOTS > searchModel.KeyFromDateRegisteredToOTS)
&& (searchModel.KeyToDateRegisteredToOTS == null || po.DateRegisteredToOTS < searchModel.KeyToDateRegisteredToOTS)
&& (searchModel.KeyFromDateDeliveredToVendor == null || po.DateRegisteredToVendor > searchModel.KeyFromDateDeliveredToVendor)
&& (searchModel.KeyToDateDeliveredToVendor == null || po.DateRegisteredToVendor < searchModel.KeyToDateDeliveredToVendor);
return expression;
}
public Func<ParcelOrder, bool> UserPrivilegeValdationExpression(string userId)
{
var roles = GetRolesForUser(userId);
Func<ParcelOrder, bool> expression =
po => po.ID == 1;
if (roles != null)
{
if (roles.Contains("ParcelAdministrator"))
expression =
po => true;
else if (roles.Contains("RegionalAdministrator"))
{
var user = db.AspNetUsers.First(u => u.Id == userId);
if (user.RegionalAdministrator != null)
{
expression =
po => po.HubID == user.RegionalAdministrator.HubID;
}
}
else if (roles.Contains("Customer"))
{
var customerID = db.AspNetUsers.First(u => u.Id == userId).CustomerID;
expression =
po => po.CustomerID == customerID;
}
else
{
expression =
po => false;
}
}
return expression;
}
If you can possibly avoid it, don't count for pagination. Just return the first page. It's always expensive to count and adds little to the user experience.
And in any case you're building the dynamic search wrong.
You're calling IEnumerable.Count(Func<ParcelOrder,bool>), which will force client-side evaluation where you should be calling IQueryable.Count(Expression<Func<ParcelOrder,bool>>). Here:
Func<ParcelOrder, bool> completeExpression = order => userPrivilegeValidation(order) && criteriaMatchValidation(order);
searchModel.PaginationTotalCount = db.ParcelOrder.Count(completeExpression);
But there's a simpler, better pattern for this in EF: just conditionally add criteria to your IQueryable.
eg put a method on your DbContext like this:
public IQueryable<ParcelOrder> SearchParcels(ParcelOrderSearchModel searchModel)
{
var q = this.ParcelOrders();
if (searchModel.KeyUploadID != null)
{
q = q.Where( po => po.UploadID == searchModel.KeyUploadID );
}
if (searchModel.KeyCustomerID != null)
{
q = q.Where( po.CustomerID == searchModel.KeyCustomerID );
}
//. . .
return q;
}

LINQ List gives null exception in where Clause

var q = from p in query
where
((criterias.birthday == p.BirthDay|| criterias.birthday == null))
&& ((criterias.marriageDate == null || criterias.marriageDate == p.MarriageDate))
&& ((criterias.gender == p.Gender) || (criterias.gender == null))
&& ((criterias.nationalities.Contains(p.Nationality)) || (criterias.nationalities == null))
criterias isa class where i store my search criterias. nationalities is a string list. the problem occurs when i have no items in string. the query throws null reference exception. the query doesnt accept null value in nationalities. how can i fix this?
Reverse the order so that the null check comes before the query: as you're using ||, the second part of the expression is only evaluated when the first part evaluates to false:
&& ((criterias.nationalities == null) ||
(criterias.nationalities.Contains(p.Nationality)))
Look at these 2:
((criterias.birthday == p.BirthDay|| criterias.birthday == null))
&& ((criterias.marriageDate == null || criterias.marriageDate == p.MarriageDate))
I don't think marriageDate will give you problems but birthday uses the wrong order.
In this case you need the 'short-circuit evaluation' property of ||, change it to:
(criterias.birthday == null || criterias.birthday == p.BirthDay)
&& (criterias.marriageDate == null || criterias.marriageDate == p.MarriageDate)
Try swapping the order of the nationalties checks. It should short-circuit on the null check before it tries to evaluate the Contains.
((criterias.nationalities == null) || (criterias.nationalities.Contains(p.Nationality)))
Turn this statement around:
(criterias.nationalities.Contains(p.Nationality)) || (criterias.nationalities == null)
so that it reads
(criterias.nationalities == null) || (criterias.nationalities.Contains(p.Nationality))
If the first operand evaluates to true, the second one will be skipped.
Try first check for null then (if it is not null) check for contains:
var q = from p in query
where
((criterias.birthday == p.BirthDay|| criterias.birthday == null))
&& ((criterias.marriageDate == null || criterias.marriageDate == p.MarriageDate))
&& ((criterias.gender == p.Gender) || (criterias.gender == null))
&& ((criterias.nationalities == null) || (criterias.nationalities.Contains(p.Nationality))

Categories