Why Task doesn't return null - c#

I'm working with the new Task Parallel Library and today went to this case:
This code doesn't compile:
internal Task<Guid?> SavePages(string[] pages)
{
return Task.Run(() =>
{
if (pages == null || pages.Length == 0)
return null;
....
Unless I explicitly returns a null nullable Guid:
internal Task<Guid?> SavePages(string[] pages)
{
return Task.Run(() =>
{
if (pages == null || pages.Length == 0)
return (Guid?)null;
// Check documents path access
Why this behavior, I'm I doing something wrong? I mean, I get the code to work with the second option but don't know If I'm misusing the library, I mean, null is always null, isn't it?
Compile error:
Cannot convert lambda expression to delegate type
'System.Func' because some of the return
types in the block are not implicitly convertible to the delegate
return type
http://msdn.microsoft.com/en-us/library/dd460717.aspx

This has to do with the way the compiler determines the type of your lambda. When you return a plain null, the only thing the compiler can imply is that you are returning an object. Hence, your parameterless lambda is compatible with Task<object>. However, the signature of your function says that you are returning Task<Guid?>, so the return type the compiler implied from your code is not compatible. When you cast that null to Guid?, you provide the compiler a the clue it is missing to make the lambda a Task<Guid?>.

This is a limitation with type inference in the C# compiler. This issue is not unrelated to the one involving the ternary operator:
int? num = a != null ? a.Value : null; // Will not compile
int? num = a != null ? a.Value : (int?)null; // Compiles
int? num = a != null ? (int?)a.Value : null; // Compiles
Another workaround for your specific situation is to specify the generic type explicitly:
return Task.Run<Guid?>(() =>
{
if (pages == null || pages.Length == 0)
return null;

Related

return statement that checks the first two characters before proceeding

return ship.DefenseType?.PropulsionMethod != null
? new BattleMethod(ship.DefenseType.PropulsionMethod)
: null;
Hi, my current return statement, above, is returning a Propulsion method if it's not null. However, my database has different types of
propulsion methods denoted by the first 2 letters in the field(PK, PA, PT, etc).
How can I check to make sure that the PropulsionMethod starts with "PK" before going further into the return statement?
In pseudo code, it might look something like this:
if (ship.DefenseType?.PropulsionMethod).startsWith("PK")
&& ship.DefenseType?.PropulsionMethod != null)
{
return new BattleMethod(ship.DefenseType.PropulsionMethod)
}
else
{
return null;
}
I tried
return ship.DefenseType?.PropulsionMethod != null &&
ship.DefenseType?.PropulsionMethod.StartsWith("PK")
? new BattleMethod(ship.DefenseType.PropulsionMethod)
: null;
But I get this error:
operator && cannot be applied to operands of type bool and bool?
Just add this condition too:
return ship.DefenseType?.PropulsionMethod != null
&& ship.DefenseType?.PropulsionMethod.StartsWith("PK")
? new BattleMethod(ship.DefenseType.PropulsionMethod) : null;
As the operator is && so the second condition will be evaluated if the first one was true (not null in this case).
You can compare nullable bool directly with true:
return ship.DefenseType?.PropulsionMethod?.StartsWith("PK") == true
? new BattleMethod(ship.DefenseType.PropulsionMethod)
: null;

Null coalescing operator vs. value()

I'm creating some objects to return to a form via API, and the objects are derived from database values, including values that could be null in the database, but cannot be null in the context of my API (I am obtaining data from multiple tables, so I know that if a field is null in one table, I can obtain a legitimate value from another table):
List<ResultsByLineShiftSlot> returnResults = new List<ResultsByLineShiftSlot>();
foreach (LineShiftSlot ls in db.LineShiftSlots.OrderBy(ls => ls.ScheduledDateAndTime).Where(ls => ls.ProductionDate == slotDate &&
ls.ShiftId == shiftId &&
ls.LineId == lineId &&
ls.Quantity > 0 &&
ls.BlendId != null))
{
var recordedResult = db.LineShiftSlotResults.FirstOrDefault(r => r.LineShiftSlotId == ls.Id);
if (recordedResult != null)
{
ResultsByLineShiftSlot returnResult = new ResultsByLineShiftSlot
{
BlendId = recordedResult.BlendId
};
}
else
{
ResultsByLineShiftSlot returnResult = new ResultsByLineShiftSlot
{
BlendId = ls.BlendId ?? 0
};
}
}
return returnResults;
In the above example, BlendId can be null in LineShiftSlots, but not in LineShiftSlotResults.
In this context where a nullable variable is known to contain a non-null value, which is better?
Should I use the null coalescing operator:
BlendId = ls.BlendId ?? 0
Or should I use .Value():
BlendId = ls.BlendId.value()
Both compile, and seem to work.
Are they functionally equivalent in this context? Is using one over the other better practice? I know that .value() could potentially return an exception, whereas the null coalescing operator could not, but in this case .value can never be null.
In the general case, they're not semantically equivalent.
labelId = recordValue.labelId.Value;
This one means I know the value can't be null. Just throw if my assumption is wrong.
On the other hand,
labelId = recordValue.labelId ?? 0;
labelId = recordValue.labelId.GetValueOrDefault();
These two mean that the value may be null, and if that happens, just ignore it, considering it's normal, and substitute it with the default value.
I'd use GetValueOrDefault() in that case, it makes it somewhat more obvious (and the JIT will inline this method).
However, your code is equivalent to this simpler alternative:
labelId = recordValue.labelId ?? otherValue;
In this case the code would be the same however have you considered the following
labelId = recordValue.labelId ?? otherValue
which is essentially the following
if(recordValue.labelId != null){
labelId = recordValue.labelId.Value;
}
else
{
labelId = otherValue;
}

Should GetHashCode() method take care about null value given as parameter?

In some C# code, I use linq GroupBy<TSource, TKey>() method with a custom IEqualityComparer<T>.
GroupBy(x => x.SomeField, new FooComparer());
The field i use as a grouping key can be null. As a consequence, i had to add some null checks in Equals() method :
public bool Equals(Foo x, Foo y)
{
if (x == null && y == null)
return true;
else if (x == null && y != null)
return false;
else if (x != null && y == null)
return false;
else
return x.Id == y.Id;
}
The question is : should I do the same in GetHashCode() function ?
public int GetHashCode(Foo obj)
{
if (obj == null) //is this really needed ?
return default(int); //
else
return obj.Id;
}
Something i do not understand : even with null keys provided in GroupBy() method, GetHashCode() is never called with a null object in obj parameter. Can somebody explain me why ? (is it just "pure chance" because the way GroupBy() is implemented and order of the elements i give to it ?)
EDIT :
as caerolus pointed it out, there is some special checks made in GroupBy() implementation.
I checked in ILSpy and GroupBy() is implemented with a Lookup<TKey, TElement>
Here is the revelant function :
internal int InternalGetHashCode(TKey key)
{
if (key != null)
{
return this.comparer.GetHashCode(key) & 2147483647;
}
return 0;
}
According to the documentation of IEqualityComparer<T>.GetHashCode:
ArgumentNullException
The type of obj is a reference type and obj is null.
So this is part of the contract of that interface, and as such you should care. Implement it by throwing ArgumentNullException if obj is null.
You should always adhere to an interface, even if you suspect or can prove that the code will never touch the parts you don't care about. Changes later might introduce code that relies on that behaviour.

Exception in IEnumerable when it's null

I have a method returning IEnumerable object, but I found that sometimes (on error) the method returns null value of IEnumerable.
The method looks something like this.
IEnumerable<string> function(String param1, String param2)
{
IEnumerable s = null;
s = (some query over here);
return s;
}
When I call this method with param2, the function internally fails and returns s which is null at this time.
So, to detect this I used,
IEnumerable<string> a = function(1,0);
if (a.count<string> > 0) //not working
if (a == 0) //not working.
What is the correct method to use IEnumerable and check whether it is null before any other operation?
you could return an empty enumerable if the search result was null:
IEnumerable<string> function(String param1, String param2)
{
IEnumerable s = null;
s = (some query over here);
return s ?? Enumerable.Empty<string>();
}
Yours s = (some query over here); is returning null. That is why you are getting the exception.
Later your check should be:
if(a != null)
and
if(a.Count() > 0)
You can combine both as:
if(a!=null && a.Count() >0)
{
// do your work
}
null is not the same as an enumeration without any elements. Therefore, your check for if(a.count<string> > 0) fails. (In fact, a isn't pointing to any instance whose number of elements you could retrieve with Count.)
Also, null is not the same as the integer value 0. Therefore, your check for if(a == 0) fails, too.
However, null is a keyword in C# and you can compare to that:
if (a == null)

How to return a 'Guid' from a 'Nullable<Guid>'?

I am trying to return a Guid value below. However the database(and my dbml) has that column as a nullable Guid and it is generating an exception on the .Select portion saying it can't convert from an IQueryable<System.Guid?> to a System.Guid.
I am guessing I need to make my return value "concrete" first???? True?
If so how do I do that with Guid's?
public static Guid GetCurrentWorkerByType(int enrollmentID, int staffTypeID)
{
using (var context = CmoDataContext.Create())
{
IQueryable<tblWorkerHistory> tWorkHist = context.GetTable<tblWorkerHistory>();
return (tWorkHist.Where(workHist =>
(workHist.EnrollmentID == enrollmentID) &&
(workHist.tblStaff.StaffTypeID == staffTypeID) &&
(workHist.EndDate == null || workHist.EndDate > DateTime.Now))
.Select(workHist => workHist.Worker));
}
}
}
// Get the Guid? itself, for sake of example from IQueryable<Guid?>
// (could be `null` from DB value or because queryable was empty)
Guid? maybeGuid = queryable.FirstOrDefault();
// Need to have *a* GUID or default it to something
// because a Guid is a value-type and needs *a* value.
Guid theGuid = maybeGuid ?? Guid.Empty;
Also see Nullable<T>.HasValue/Value -- A longer, but equivalent, method would be:
Guid theGuid = maybeGuid.HasValue ? maybeGuid.Value : Guid.Empty;
Observe that HasValue may be suitable in general if statements to change logic and also note that Value will throw an exception if maybeGuid is "has no value" -- is null -- which is why the guard is required.
Happy coding.
Pedantic detail: The equivalent method is not "thread safe". That is, assuming maybeGuid was shared, it could be assigned null between HasValue and Value. There are a number of SO questions that cover the "thread safety" of ?? (the coalesce operator) -- the generated IL effectively uses a temporary variable so the value may be stale but an exception can't be thrown.
Use
.Select(workHist => workHist.Worker).Single();
.Select() returns a query that has not run.
If you use .Select().ToList() then you you return a list.
If you use .Select().Single() then you return one item and it makes sure only one item is there
If you use .Select().SingleOrDefault() then you return one item and default. Query must not contain more than 1 item.
If you use .Select().First() then you return the first item. Query must contain at least 1 item.
If you use .Select().FirstOrDefault() then you return the first item or default. Query can contain 1 or more or no items.
Try
Change your return type from System.Guid to ?System.Guid // nullable of guid
Then add .FirstOrDefault() after the select call
A struct cannot be null, but the System.Nullable class wraps the struct in a class.
What you've got is a query that hasn't executed for one, and for two, it will return a list of Guids as far as I can tell. If you want to return the first Guid or default (which I believe is a zero'd out guid) you can say .FirstorDefault() after your select.
The closest you will get representing null with a Guid is to use Guid.Empty. So, for your query, you will probably want to first pick the value returned by FirstOrDefault, make a null check, and then return a reasnable value:
Guid? result = tWorkHist.Where(workHist =>
(workHist.EnrollmentID == enrollmentID)
&& (workHist.tblStaff.StaffTypeID == staffTypeID)
&& (workHist.EndDate == null || workHist.EndDate > DateTime.Now))
.Select(workHist => workHist.Worker)
.FirstOrDefault();
return result.HasValue ? result.Value : Guid.Empty;
Use FirstOrDefault with conjunticon with Guid.Empty
Try this:
public static Guid GetCurrentWorkerByType(int enrollmentID, int staffTypeID)
{
using (var context = CmoDataContext.Create())
{
IQueryable<tblWorkerHistory> tWorkHist = context.GetTable<tblWorkerHistory>();
var guid = (tWorkHist.Where(workHist => (workHist.EnrollmentID == enrollmentID) &&
(workHist.tblStaff.StaffTypeID == staffTypeID) &&(workHist.EndDate == null || workHist.EndDate > DateTime.Now))
.Select(workHist => workHist.Worker)
///####NOTICE THE USE OF FirstOrDefault
).FirstOrDefault();
return (guid.HasValue)?guid.Value:Guid.Empty
}
}

Categories