Reputation: 357
I would like to be able to having a class with properties, but have some way of "namespacing" the properties.
In the end I would like to have a class:
Class Employee
{
public string Name {get; set;}
private class/namespace/something HomeAddress
{
public string Street {get; set;}
}
}
I would like to be able to go:
Employee emp = new Employee();
emp.Name = "Joe";
emp.HomeAddress.Street = "Best St.";
Is this even possible? (or best practice, what is best practice anyway for something like that?) I know I can create separate classes, initialize them in the Employee Constructor and go from there...
But I would like to hide the nested classes since they will only be used in the Employee class. I would like to avoid having this:
HomeAddress home = new HomeAddress();
home.Street = "Worst St.";
I would like to hide this from the intellisense list and not have it be something that can be created on its own so only the Employee class is visible for someone to create since these sub helper classes will only be used inside other objects and never on their own.
There is another example from another question:
class Fruit{
public void eat(){
MessageBox.Show("Fruit eaten");
}
public string color = "red";
//you have declared the class but you havent used this class
public class physicalProperties{
public int height = 3;
}
//create a property here of type PhysicalProperties
public physicalProperties physical;
}
But this isn't quite what I was after either since physicalProperties is public. You would still be able to:
Fruit.physicalProperties fruitProp = new Fruit.physicalProperties();
And use this outside of the Fruit class.
I have a feeling I am chasing after something that I am never going to find, but I am curious if anyone else has ever had to need to do something like this? It seems when you build out an application you end up with reams of objects in the intellisense list, of which some are landmines since if someone saw HomeAddress they might think it is useful for something. If only Employee showed up in the intellisense list then they would be on the right track from the start, creating the Employee object and then modifying everything associated with that employee.
Having all the supporting junk in the same intellisense list as the main objects you are supposed to be working with seems to add noise and distraction, especially if the person doing the coding isn't familiar with your library. It seems to me that this way would be a subtle guide as to what you should be creating, and once you create it how you should be manipulating it...
Upvotes: 0
Views: 154
Reputation: 22945
To prevent the creating of an address, I would do the following. The interface is public, but the implementing nested class is private.
public class Employee {
#region Constructor(s)
public Employee() {
HomeAddress = new Address();
}
#endregion
#region Properties
public string Name { get; set;}
public IAddress HomeAddress { get; private set; }
#endregion
#region Nested
public interface IAddress {
string Street { get; set; }
}
private class Address: IAddress {
public string Street { get; set;}
}
#endregion
}
After reading @Moeri's answer, you could also create the instance lazily instead of in the constructor.
Upvotes: 2
Reputation: 26446
You can't have "nested properties" without specifying a type for each nest level. Furthermore, the type of each level will have to be accessible to the caller (public).
But you can avoid the need for this:
HomeAddress home = new HomeAddress();
home.Street = "Worst St.";
By creating the new HomeAddress
from within the Employee
constructor:
public Employee()
{
this.HomeAddress = new HomeAddress();
}
public HomeAddress HomeAddress
{
get;
private set;
}
No one can assign a new HomeAddress
to the property, but they can change the values of HomeAddress
.
One other thing to remember is that if you have a nested class Employee.HomeAddress
, the property cannot be of the same name.
Upvotes: 1
Reputation: 9294
What about nesting the Address class in the Employee class and automatically initializing it lazily if needed.
public class Employee
{
public string Name {get; set;}
private Address _homeAddress;
// only contains a getter, which auto-initializes the value to avoid NullReferenceException
// this auto initialization is also useful to declutter your constructors
public Address HomeAddress
{
get { return _homeAddress ?? (_homeAddress = new Address()); }
}
public class Address
{
// only classes from the same assembly can create addresses
internal Address() {}
public string Street {get; set;}
}
}
Upvotes: 1