Filtering my property in a getter - c#

Here is my code:
private Analyst _PrimaryAnalyst;
public Analyst PrimaryAnalyst
{
get
{
Analyst activeAnalysts;
if (this.PrimaryAnalyst.IsActive == true)
{
activeAnalysts = _PrimaryAnalyst;
}
return activeAnalysts; //"Use of unassigned local variable"
}
set
{
SetPropertyValue("PrimaryAnalyst", ref _PrimaryAnalyst, value);
}
}
Basically I am trying to filter my Analyst property based on if they are marked Active or not. Then I want to to return only Active Analysts. (Based on a bool property of Analyst), I am getting an error on the return statement saying "Use of unassigned local variable"
However I am clearly assigning it in the if statement?

In C# you can not use a local variable before assigning it a value.
C# Language Specification, section 1.6.6.2
C# requires a local variable to be definitely assigned before its
value can be obtained
lets get to your code
what happen if this.PrimaryAnalyst.IsActive is false? Yes, Use of unassigned local variable
you can fix this by initializing the local variable.
Analyst activeAnalysts = null;
or
if (this.PrimaryAnalyst.IsActive == true)
{
activeAnalysts = _PrimaryAnalyst;
}
else
{
activeAnalysts = null;
}
but there is another problem here. Your code leads to StackOverflowException because you are calling a method inside itself (recursion) but there is no way out of it so it leads to StackOverflowException
you should change the line this.PrimaryAnalyst.IsActive == true to _PrimaryAnalyst.IsActive == true

Change the first line of the getter to:
Analyst activeAnalysts = null;
The issue is that if the if statement evaluates to false, then the value is never set, so the compiler doesn't know what it should return.

The reason you're getting the error is that not all code paths lead to an assignment. You should either initialize the variable before the if, or include an else and assign it to something there.
Also, you should be checking your private variable in the if statement instead of the public one (to avoid a StackOverflowException), and, assuming that Analyst is a nullable class, you should also ensure it's not null before checking IsActive. A property getter should not throw an exception.
Your getter can be also be simplified using a ternary assignment:
get
{
return (_PrimaryAnalyst != null && _PrimaryAnalyst.IsActive)
? _PrimaryAnalyst
: null;
}

Related

How to tell C# nullable type checker that a variable cannot be null after a function call returns?

Short Version
How to make the C# nullable type checking compiler realize that the variable customer cannot be null after the call returns:
Constraints.NotNull(customer);
.NET Fiddle: https://dotnetfiddle.net/ZcgRCV
Long Version
If i have code like:
#nullable enable
Customer? c;
...
Console.WriteLine(customer.FirstName);
The compiler will (correctly) warn me that customer might be null when i try to access .FirstName:
customer.FirstName ⇐ possible null dereference
Guard Constraint
I want to perform a guard, or a constraint that will tell the C# 8 nullable type checker that the value cannot be null. I'll call a function that guarantess that the variable cannot be null after the function returns:
#nullable enable
Customer? customer;
...
Constraint.NotNull(customer, "Customer"); //if this function returns customer is definitely not null
Console.WriteLine(customer.FirstName);
Where Constraint.NotNull is something like:
public static class Constraint
{
public static void NotNull(Object? o, String msg="")
{
if (o == null)
throw new Exception("Object cannot be null "+msg);
}
}
And the guard does its job; it raises an exception. But the compiler doesn't realize that customer cannot be null after Constrant.NotNull returns:
Another Example
A better example, i came across in some old code:
Customer? currentCustomer;
//...
EnsureCurrentCustomer();
DoSomethingWithIt(currentCustomer); // guaranteed not null because EnsureCurrentCustomer did it,
// but the compiler doesn't know that.
We need a way for EnsureCurrentCustomer to tell the C# 8 nullable type checker that the variable currentCustomer cannot be null after EnsureCurrentCustomer function returns.
How do?
Attempt 1: Null forgiving (!) operator
No. I want to work with the type system, not hide the land-mines (as Microsoft reminds you)
Attempt 2: https://stackoverflow.com/a/58282043/12597 (gives its own error)
Attempt 3: https://stackoverflow.com/a/65076221/12597 (No, see #1)
ChatGPT says the only way to do it is to use the JetBrains [NotNull] constraint; which i don't have access to.
If you just change the call site ever so slightly:
customer = Constraint.NotNull(customer, "Customer");
Then you can just do:
public static class Constraint {
public static T NotNull<T>(T? t, string? msg="") where T: notnull {
if (t is null) {
throw new Exception("Object cannot be null "+msg);
}
return t;
}
}
For the second example, assuming currentCustomer is a field, you can use MemberNotNull:
[MemberNotNull("currentCustomer")]
void EnsureCurrentCustomer() {
if (currentCustomer is null) {
throw new Exception(...);
}
}
If currentCustomer is instead a local variable and EnsureCurrentCustomer is actually a local function, then I would do something similar to Constraint.NotNull, i.e. changing the caller to:
currentCustomer = EnsureCurrentCustomer()
and just use a non nullable Customer for the return type.
This is achieved using the [NotNull] annotation on the argument being verified in your guard-clause method. A good reference for this is in the ArgumentNullException.ThrowIfNull static method. The summary of the NotNullAttribute says:
Specifies that an output will not be null even if the corresponding type allows it. Specifies that an input argument was not null when the call returns.
You can also refer to xUnit's Assert.NotNull assertion, which does the same thing.

Use of unassigned local variable (Object) Created from Stored Procedure

I am creating an instance of a class from a stored procedure but I get the following error:
Use of unassigned local variable 'member'
I have the following code:
Member member;
while (rdr.Read())
{
member = new member(rdr.GetInt32, rdr.GetString(1)); // Populate Class from Stored Procedure
}
return member
I realise that the compiler does not know that the while loop will always be triggered however what is the cleanest way to solve this without creating a default constructor?
The compiler can't determine whether your condition for loop will be true and member would be initialized. Therefore the error.
Since you are returning member after the loop and instantiation is done inside the loop. It is not guaranteed that member would be initialized/assigned a value. rdr.Read() could return false in first iteration.
You can do:
Member member = default(Member); //null for reference type
while (rdr.Read())
{
member = new member(rdr.GetInt32, rdr.GetString(1)) // Populate Class from Stored Procedure
}
return member;
The other error in your code is usage of rdr.GetInt32, it is a method and should have column ordinal specified like :
rdr.GetInt32(0)
Problem :
You should assign the member variable before while loop, as compiler could not identify wether loop will be executed for sure or not.
you need to specify the column number while using GetInt32() function.
Solution :
assign memebr to null initially.
use required column index in GetInt32() function.
Try This:
Member member=null;
while (rdr.Read())
{
member = new member(rdr.GetInt32(0), rdr.GetString(1)); // Populate Class from Stored Procedure
}
return member;

How to check if DateTime object was not assigned?

So, First of all. Code:
I've got a class:
public class Myobject
{
public string Code { get; set; }
public DateTime? StartDate { get; set; }
}
And this is part of very simple source:
MyObject mo = new MyObject();
mo.Code= "sth";
// NO action on StartDate property!
if (mo.StartDate.HasValue)
{
sc.Parameters.Add(new SqlParameter("#inStartDate", mo.StartDate.Value));
}
else
{
sc.Parameters.Add(new SqlParameter("#inStartDate", DBNull.Value));
}
Simple 'if' - Sql Server 2008, throw an error - when gets null Datetime (it has to be DBNull.Value)
So I want to check it first, and then pass right value or DBNull.
My problem is - this 'if' always retruns true! Why!?
Also tried that:
if (mo.StartDate.Value == null)
but it always returns false. How come it is not a null? It was not even created..
So.. How to check if DateTime object was not assigned?
Try this:
if (mo.StartDate.GetValueOrDefault() != DateTime.MinValue)
{
// True - mo.StartDate has value
}
else
{
// False - mo.StartDate doesn't have value
}
should just be able to do
mo.StartDate != null
instead of
mo.StartDate.Value != null
Running the simplest test with that class (as you presented it) yields false:
var mo = new Myobject();
Console.WriteLine(mo.StartDate.HasValue);
Output is False.
I'd put a breakpoint on your constructor (if you have one), make sure nothing else is getting assigned, and walk through any methods called along the way to make sure there's nothing else setting the property that may not be immediately obvious...
Can you post more code, perhaps? There must be something in code not posted setting the property.
.HasValue and ==null are the ways to check whether DateTime? is assigned a value or not. You are doing it right. There might be problem somewhere else that .HasValue returns true always.
The way you're checking for null is fine, there must be something else that's setting the field's value.
To find what's setting the field you could right-click it then do find all references, then scan the list for any assignments.
Failing that, you could change it to an explicitly defined property temporarily and set a breakpoint within the set method, then execution will pause whenever the value is set and you can look up the call stack.

Is this redundant code?

I'm upgrading a system and am going through another developers code (ASP.NET in C#).
I came across this:
private ReferralSearchFilterResults ReferralsMatched
{
get
{
if (Session[SESSION_REFERRAL_SEARCHFILTERRESULTS] == null || Session[SESSION_REFERRAL_SEARCHFILTERRESULTS].GetType() != typeof(ReferralSearchFilterResults))
return null;
else
return (ReferralSearchFilterResults)Session[SESSION_REFERRAL_SEARCHFILTERRESULTS];
}
set
{
if (value == null)
{
Session[SESSION_REFERRAL_SEARCHFILTERRESULTS] = value;
}
else if (value.GetType() == typeof(ReferralSearchFilterResults))
{
Session[SESSION_REFERRAL_SEARCHFILTERRESULTS] = value;
}
}
}
Is checking the type on the setter unnecessary? Surely, if I set the property to something other than a ReferralSearchFilterResults object, the code wouldn't even compile? Am I missing something or am I right to think this can be achieved just by using:
set
{
Session[SESSION_REFERRAL_SEARCHFILTERRESULTS] = value;
}
The original code prevents any subclasses of ReferralSearchFilterResults from being set or get to or from the property. This is because value.GetType() will return the actual Type of the object referenced by value. If that Type is a subclass of ReferralSearchFilterResults, then it will not equals typeof(ReferralSearchFilterResults).
I'm not sure of your context here, so I can't tell you whether that's correct behaviour or not. If it's intended behaviour, it does smell a bit dirty as it will silently ignore any assignments of subclasses. But I can't really judge without more context.
I think you're right - the setter shouldn't compile if provided with something of that cannot be implicitly cast to a ReferralSearchFilterResults.
For the get part, you can use
return Session[SESSION_REFERRAL_SEARCHFILTERRESULTS] as ReferralSearchFilterResults;
This returns the value if it can be casted to ReferralSearchFilterResults, otherwise null.
Jamie you are correct. The Type check on the Setter is unnecessary in this case because value must be a ReferralSearchFilterResults.
One other change you might consider is using the is and as keywords in place of comparing Type objects.
private ReferralSearchFilterResults ReferralsMatched
{
get
{
if (Session[SESSION_REFERRAL_SEARCHFILTERRESULTS] == null || !(Session[SESSION_REFERRAL_SEARCHFILTERRESULTS] is ReferralSearchFilterResults))
return null;
else
return Session[SESSION_REFERRAL_SEARCHFILTERRESULTS] as ReferralSearchFilterResults;
}
set
{
Session[SESSION_REFERRAL_SEARCHFILTERRESULTS] = value;
}
}
Session variables are of type object, so you can store anything inside those. But in this case the setter itself prevents the programmer from assigned an other object type than ReferralSearchFilterResults and derived objects.
So the check, as you pointed out, itself is unneccessary. Additionally it does not let a programmer assign a object that derives from ReferralSearchFilterResults.
But I would use Session.Remove rather than just setting the variable to null, because the session variable would still exists in the http context if only set to null.
So:
set
{
if (value == null)
Session.Remove(SESSION_REFERRAL_SEARCHFILTERRESULTS);
else
Session[SESSION_REFERRAL_SEARCHFILTERRESULTS] = value;
}
I can understand the type check in the get bit, but as you say, in the setter, you can't pass in anything that's not a ReferralSearchFilterResults, as the code would fail at the time of compilation.
(Could be some old habit, the other developer had)

Good practices for initialising properties?

I have a class property that is a list of strings, List.
Sometimes this property is null or if it has been set but the list is empty then count is 0.
However elsewhere in my code I need to check whether this property is set, so currently my code check whether it's null and count is 0 which seems messy.
if(objectA.folders is null)
{
if(objectA.folders.count == 0)
{
// do something
}
}
Any recommendation on how this should be handled?
Maybe I should always initialise the property so that it's never null?
When I have List as a property, I usually have something that looks like the following (this is not a thread safe piece of code):
public class SomeObject
{
private List<string> _myList = null;
public List<string> MyList
{
get
{
if(_myList == null)
_myList = new List<string>();
return _myList;
}
}
}
Your code would then never have to check for null because the Property would be initialized if used. You would then only have to check for the Count.
Right now your code will Always throw a Null Pointer exception, you are checking for Null and if it IS null - you're trying to access an object which does not exist.
If for your application the collection being a null reference never has a different meaning than the collection being empty, then yes, I would say you should always initialize it and this way remove the null checks from the remaining code.
This approach only makes sense if the property setter does not allow to change it to a null reference after initialization.
You have three options (and you need to decide based on your project):
Create a method to check for NullOrNoElements. Pro: Allows both null and no entries. Con: You have to call it everywhere you want to use the property.
Preinitialize with a list. Pro: Thread-save and very easy. Con: will use memory even when not used (depending on how many instances you have this may be a problem)
Lazy initialize Pro: Does only use memory when really used. Con: NOT thread save.
private List<string> lp = null;
public List<string> ListProp
{
get
{
if(lp == null)
lp = new List<string>();
return lp;
}
}
You could always initialize the property so it's an empty List. Then you can just check the count property.
List<String> Folder = Enumerable.Empty<String>();
I once wrote an extension method for ICollection objects that checked if they were null or empty
public static Boolean IsNullOrEmpty<T>(this ICollection<T> collection)
{
return collection == null ? true : collection.Count() == 0;
}
public static Boolean IsPopulated<T>(this ICollection<T> collection)
{
return collection != null ? collection.Count() > 0 : false;
}
You could do this in a single IF
if(objectA.folders is null || objectA.folders.count == 0)
Or you could create a boolean property in the class which checks this status for you and returns a result
public bool objectA.FolderIsNullOrEmpty
{
get { return objectA.folders is null || objectA.folders.count == 0;}
}
If it does not make a difference to your application, I would rather recomend initializing the List to start with.
You could handle this by initializing the object in the constructor. This is usually where this type of thing is done. Although I see nothing wrong with your current code. No point in initializing stuff that doesn't exist yet, it just wastes memory.
Its a good question. I would add a method to objectA FoldersNullOrEmpty() that you can use eg
public virtual FoldersNullOrEmpty()
{
return (folders == null || folders.count == 0)
}
I almost always initialize lists and even make sure they can't be set to null if exposed by any setters. This makes using them much easier.

Categories

Resources