简体   繁体   中英

object is always not null

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("service@tradertoolkit.com");
        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

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.

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, eg

 var mailClient = SmtpHelper.CreateClient(credentials);
 if (mailClient == null)
 {
     throw new Exception("SmtpHelper returned a null client!");
 }

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);
 }

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM