Reputation: 5162
This has always driven me crazy and I still cant get my head around it. In the code below, the if statement is flagged by the editor saying that the "expression is always true"
public Task ConfigSendMailAsync(IdentityMessage message)
{
const string usertoken = "Sent";
var mailMessage = new MailMessage();
mailMessage.To.Add(new MailAddress(message.Destination));
mailMessage.From = new MailAddress("[email protected]");
mailMessage.Subject = message.Subject;
mailMessage.Body = message.Body;
var credentials = new NetworkCredential(
ConfigurationManager.AppSettings["mailAccount"],
ConfigurationManager.AppSettings["mailPassword"]
);
var mailClient = new SmtpClient {Credentials = credentials};
***if (mailClient != null)***
{
mailClient.SendAsync(mailMessage, usertoken);
return Task.FromResult(0);
}
else
{
//log error
return Task.FromResult(-1);
}
}
How is it always true, what if the message that was passed was invalid, what if there was a failure creating the credentials, etc. etc. Certainly something COULD make that if statement true. I get that if anything failed prior, I'd get an exception. If I wanted to ensure the credential was valid, Id certainly test for that.
if (credentials != null)
{
}
But guess what, apparently thats always true as well. How can that be, what if there was nothing stored in those app settings? Can someone explain how this actually works and how best to structure this code
Upvotes: 0
Views: 226
Reputation: 2509
How is it always true, what if the message that was passed was invalid, what if there was a failure creating the credentials, etc. etc.
In that case, perhaps an exception would be thrown, and the if
would never be reached. You can trust the compiler on this one.
Same for credentials: You give an example of invalid credentials. They would be invalid, sure, but not null.
The only way you could have your if to return false would be if you swallow an exception occuring in the constructor (which would be a terrible idea, and the compiler would detect it and not display that warning any longer)
for instance:
try
{
var mailClient = new SmtpClient {Credentials = credentials};
}
catch(Exception)
{
// Evil: you swallow your exception, mailClient is null
// The program continues and god drowns a kitten.
}
if (mailClient != null)
{
mailClient.SendAsync(mailMessage, usertoken);
return Task.FromResult(0);
}
Upvotes: 1
Reputation: 14369
The condition (mailClient != null)
is only a reference check.
If the variable mailClient
would be a dangling pointer, this condition would fail. As long as you have a valid space carved out in memory with mailClient
pointing to that memory space, it is not null.
The conditional that you are concerned with would ask - Does the mailClient
point to anything valid? And the CLR would find out - Yes, the value in the reference type variable called mailClient
is valid. The conditional would then be true
as it is not null.
When you do var xyz = new Something();
you reserve a piece of memory and the variable now points to that memory in the heap. Even if you have not populated the fields of that member, the address stored in xyz
not null anymore and that is how your conditional is always true
.
Opposed to that, let's say you have a statement Something xyz;
. All this means that xyz
can store the address of a Something
type object. However, this variable does not point to any valid address in memory space yet and is just a dangling pointer. This will cause your conditional check of (xyz != null)
to fail.
Upvotes: 0
Reputation: 52210
In the code that you have, mailClient is never null, because your code just instantiated it. If there were a problem with the instantiation, the line above would have failed.
var mailClient = new SmtpClient {Credentials = credentials}; //This line would throw an error if SmtpClient could not be instantiated
if (mailClient == null)
{
throw new Exception("This will never happen.");
}
You would need the null check only if you are using some function or factory pattern to create the object instance, e.g.
var mailClient = SmtpHelper.CreateClient(credentials);
if (mailClient == null)
{
throw new Exception("SmtpHelper returned a null client!");
}
Upvotes: 1
Reputation: 6531
mailClient is never null
You just new'd it up. Maybe the field/property is null, that's not what you're checking there. Maybe something went terribly wrong and an exception was thrown and mailClient was never assigned, but then you wouldn't have got to that check.
Also this is how you write asynchronous code. Also, it's not SQL, we don't comminicate whether an method worked by returning a weakly typed integer.
Upvotes: 0
Reputation: 59228
Creating the SmtpClient
object does not check the credentials for validity. It will just store them in fields for later use. The constructor will create a new object and the object will not be null. Conclusion: the if statement is always true
.
What will happen though: the SendAsync()
method may throw a SmtpException if credentials don't work. You'd need to catch the exception.
Upvotes: 1