0

Hey guys kind of a simple question, I'm not exactly sure where/how to initialize a new object instance so I don't get this error. I have a class object(Contact) that has another class object(ContactInfo) and sometimes the user decides not to input(instantiate) the ContactInfo object. So later when I try to do a search via Contact.ContactInfo, I get the error. Below I have the line of code where I get the error and then I have the two classes:

foreach (var Contact in Contacts)
{
    if (String.Equals(Contact._contactInfo.City.ToLower(), city, StringComparison.CurrentCulture))
    {
        ContactsByCity.Add(Contact);
    }
}

and then the two classes:

public class Contact : Person
{
    private ContactInfo info;
    private ContactInfoLoader loader;
    public ContactInfo _contactInfo { get; set; }

    public Contact()
    { }
    public Contact(ContactInfo _info)
    {
        info = _info;           
    }
    public ContactInfo GetContactInfo()
    {
        loader = new ContactInfoLoader(this);
        return loader.GatherContactInfo();
    }     
}

public class ContactInfo
{
    public string PhoneNumber { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string State { get; set;}

    public ContactInfo()
    { }

}
Paul Roub
  • 36,322
  • 27
  • 84
  • 93

4 Answers4

1

If you want to guarantee that the ContactInfo info won't be null after the Contact is constructed, you'll need to check for that at the time of construction. Consider something like this:

public class Contact : Person
{
    private ContactInfo info;
    public ContactInfo _contactInfo { get; set; }

    public Contact(ContactInfo _info)
    {
        if (_info == null)
            throw new ArgumentNullException("_info");
        info = _info;
    }
    public Contact(ContactInfoLoader loader)
        : this(loader.GatherContactInfo())
    {
    }
}

Bonus:

A more standard style for the class definition but with equivalent semantics would be

public class Contact : Person
{
    //auto-generates a private field for you
    public ContactInfo Info { get; private set; }

    public Contact(ContactInfo info)
    {
        if (info == null)
            throw new ArgumentNullException("info");
        this.Info = info;
    }
    public Contact(ContactInfoLoader loader)
        : this(loader.GatherContactInfo())
    {
    }
}
Timothy Shields
  • 75,459
  • 18
  • 120
  • 173
  • I like the Bonus code but when I make the call to create a new Contact, I get errors such as: – user2359626 May 08 '13 at 21:39
  • 'AddressBook.Contact does not contain a definition for 'ContactInfo' from the following line: String.Equals(Contact.ContactInfo.City.ToLower(). Also I get a 'AddressBook.Contact does not contain a definition for getContactInfo' – user2359626 May 08 '13 at 21:57
  • Another issue, when I create a new Contact, I never have a ContactInfo or ContactInfoLoader already instantiated to pass in to the Contact constructors. I know I'm doing something really wrong here, I can't figure it out – user2359626 May 08 '13 at 21:59
  • @user2359626 You should take advantage of the vast amount of available resources on the web for teaching you C#. These new problems you're encountering are extremely basic. – Timothy Shields May 08 '13 at 22:05
0

If you're just looking to avoid the exception, you can say:

if (Contact._contactInfo && 
    String.Equals(Contact._contactInfo.City.ToLower(), city,
                  StringComparison.CurrentCulture))
{
    ContactsByCity.Add(Contact);
}

alternatively, your parameterless constructor could add an empty ContactInfo object:

public Contact()
{
  _info = new ContactInfo();
  // and make sure the ContactInfo constructor creates non-null, City etc.
}
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
  • By adding an empty ContactInfo object, how would I make the ContactInfo constructor create non-null properties (city, state, etc)? – user2359626 May 08 '13 at 21:48
  • Within `public ContactInfo()`, set `City = ""; State = "";` and so on. – Paul Roub May 08 '13 at 21:50
  • When I create a new Contact, I never have a ContactInfo or ContactInfoLoader already instantiated to pass in to the Contact constructors. I know I'm doing something really wrong here, I can't figure it out. For example: newContact.GetContactInfo(); // Here I want a Contact to add ContactInfo to it. under my AddContact method: Contact newContact = new Contact(); and: if (String.Equals(Contact.ContactInfo.City.ToLower(), city, StringComparison.CurrentCulture)) I never make a call with Contact having ContactInfo or ContactInfoLoader being passed in as a parameter. – user2359626 May 08 '13 at 22:05
0

In your parameterless constructor for Contact, I would instantiate a new ContactInfo object.

public Contact()
{ 
    info = new ContactInfo();
}

This will ensure that no matter which constructor gets called, any instantiated Contact object will have a non-null ContactInfo object associated with it.

If a null ContactInfo object is passed into your Contact constructor, you could do the following:

public Contact(ContactInfo _info)
{
   if(_info == null)
       _info = new ContactInfo();

   info = _info;
}
gwin003
  • 7,432
  • 5
  • 38
  • 59
0

If the contract of the class is that ContactInfo can be null (because perhaps it is valid that a Contact not have ContatctInfo) then consumers will need to check for null before using the returned ContactInfo.

If, on the other hand, Contact is never valid without a ContactInfo then only provide constructors that take a ContactInfo and if that ContactInfo is null, it should throw an ArgumentNullException

Matt Smith
  • 17,026
  • 7
  • 53
  • 103
  • Ok if I use the bonus code, how do I make the proper call to create new ContactInfo for a specific contact: newContact.GetContactInfo(); String.Equals(Contact.ContactInfo.City.ToLower() – user2359626 May 08 '13 at 21:52
  • BIG THANKS TO EVERYONE!!! I got it working and implemented much of what everyone said. Thanks! – user2359626 May 08 '13 at 23:18
  • @user2359626 If you want to "thank" someone on here for a good answer, upvote their question. Then, pick the answer you think is the best answer (if there is one), and click the "check" to mark it as the answer. – Matt Smith May 09 '13 at 14:27