Nested Properties / Classes - c#

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...

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.

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

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.

Related

What is the best way to handle multiple (potentially null) navigation properties?

I have 3 classes
public class ActivityLog
{
// The activity log affects an employee
public int EmployeeID { get; set; }
public Employee Employee { get; set; }
// The activity log affects a department
public int DepartmentID { get; set; }
public Department Department { get; set; }
}
In this example there are two different object types that could be displayed on the view, but in reality there are much more types that differ and for which it doesn't seem sensible to move it to its own inheritance model.
I would like to be able to do the below:
public class ActivityLog<T>
{
// The activity log affects an unknown type
public T ConcernedObjectID { get; set; }
public T ConcernedObject { get; set; }
}
Right now we have a lot of null checks in our view (if employee is null then use department).
Is this something that entity framework can help with somehow, or would it be best to implement a code only solution (e.g. Interfaces)?
I think you have a design problem here. The ActivityLog class tries to do too much. Its both an entry in the log for an employee and for a department. Which are completely different things. The only thing they have in common is that they can be put into an activity log.
I would either use a common interface or an abstract base class. You can then use the asp.net equivalent of data templates to visualize the data.
So something like this:
public abstract class ActivityLogEntry
{
int Id { get; }
}
public EmployeeActivityLogEntry : ActivityLogEntry
{
Employee Employee {get;}
}
public DepartmentActivityLogEntry : ActivityLogEntry
{
Department Department {get;}
}
Another thing that can help you with null checks is to make it explicit that something can be null. I use the Optional NuGet package for that. This gives you something like this
Option<Employee> Employee {get; }
public string ToString()
{
return this.Employee.Match(e => e.Name, () => "");
}
In this case you cannot directly access the Employee that is captured in the Option. Instead you have to provide a Func for what to do when there is an Employee (its not null) and for when there isn't. There are a lot more helper functions in the optional library. It makes it a lot clearer that you need to handle both cases. You can no longer be surprised by something begin null.
(Of course you should not use Option<T> for everything. Only use it on properties that can sometimes be null. Not on properties that should never be null, or you start hiding bugs from yourself).

Is that the good thing to create object in same class itself ? does it make any memory leakage issue in .net

for e.g I have a class student and in same class the object is created itself.
class student
{
public static void Main ()
{
//......
//......
}
student s= new student();
}
If you declare the class as your sample code shows it will not work.
You use an initializer that creates an instance (of the same type) that will call the initializer that creates an instance that will call the initializer...
You'll end up in an StackOverflowException.
If you need a nested structure of the same kind you should think of creating it lazy on first access.
Maybe the code could look like this:
class student
{
Lazy<student> s = new Lazy<student>(() => new student());
}
This will give you the possibility to create an instance. At the first access of s.Value a new instance of student will be created. The logik of iterating over all instances will create an StackOverflowException or not.
A singleton is created as a static variable.
class StudentSingleton
{
public static readonly StudentSingleton Instance = new StudentSingleton();
private StudentSingleton() { }
}
The difference is that there is no instance variable created of the same kind.
class A
{
public A InstanceA{get; set;}
}
It's called self-association and though it is a common practice in some cases but you'd better avoid using it without a good cause.
Check this for example:
http://sce.uhcl.edu/helm/rationalunifiedprocess/process/modguide/md_assoc.htm#Self-Associations
Some example:
public class Person
{
public string Id {get; set;}
public string Name {get; set;}
public DateTime BirthDay {get; set;}
// ... some other properties
public Person Father {get; set;}
public Person Mother {get; set;}
}
Here we use self-association in class because instance of Person in analogy to real life certainly knows who his parents are and they are Persons too.
As to your case just change code to:
class Student
{
}
class Program
{
public static void Main ()
{
//......
//......
Student s = new Student();
}
}

How do I create an auto-implemented list property in a class in C#?

To begin with I made a class with fields like this:
class Person
{
public string name;
public List<Thing> things = new List<Thing>();
public Person(string name)
{
this.name = name;
}
}
and directly changed the field things outside the class, but later found out that this is not the best practice as the fields of class should be private and accessed using public properties instead. I decided to change these fields into auto-implemented properties, as I currently don't require any validation within the properties:
class Person
{
public string Name { get; set; }
public List<Thing> Things { get; set; }
public Person(string name)
{
this.Name = name;
}
}
According the MSDN page for auto-implemented properties (https://msdn.microsoft.com/en-us/library/bb384054.aspx), the compiler creates a private backing field for the property.
However, with a list property I'm not sure whether the compiler automatically instantiates the list backing field, so my question is will having the lists as auto-implemented properties work as in the second example above, or do I need to instantiate the lists as well, and if so how should I do this?
I'm not sure whether the compiler automatically instantiates the list backing field
It doesn't. If you don't instantiate it, it will be null by default.
do I need to instantiate the lists as well, and if so how should I do this?
You need to instantiate it yourself. This is usually/can be done in the constructor. E.g:
public Person(string name)
{
this.Name = name;
this.Things = new List<Thing>();
}

Best way to pass control values from form to separate class

I have a WinForms application that creates a huge, custom textfile. To do this requires the user to configure dozens of controls on the main form and then click a Submit button. What is the best way to pass all those control values to my Generator class? The problem is I'm ending up with 20+ parameters to pass to a Generate() method. I can group some of those into Config objects (i.e. the date/time controls can be passed into a DateTimeConfig object) and then pass these config objects into the Generate() method to minimize the number of parameters needed, but it still feels like there must be a better way. Any ideas?
EDIT: Thank you for your responses, but I was hoping for something other than a configuration object (as that's what my OP mentioned). I guess what I was hoping for is some way to serialize the values of all the controls automatically, without having to build a custom object and then modify that everytime a control changes or gets added/removed.
Why not create a custom object class as container of your data and then pass the istance of this class to the Generator method as parameter?
Look into Model Driven Development, where the parameters are grouped into business objects or data transfer objects (DTOs). This is a more intuitive way to group parameters than by datetime, etc.
If you place those model objects in a separate project, you can pass those objects around the solution (from one method to another and one project to another) without having to serialize them or mess with long parameter list ordering. You can even nest model objects inside other model objects.
In this example, notice you only have to change parameters in the Person object or the Address object and you never have to serialize or map anything:
// this is my business model object
public class Person
{
public int PersonId { get; set; }
public string PersonName { get; set; }
// notice the Address object nested in the Person class
public Address HomeAddress { get; set; }
}
// this is another class that lives inside the person class
public class Address
{
public string Street { get; set; }
public string City { get; set; }
}
In one class you could have this method that receives a person with an address and passes the person to another class's SavePerson class:
public void ProcessPerson(Person person)
{
person.PersonName = "Robert";
Address address = new Address();
address.City = "Austin";
person.Address = address;
SavePerson(person);
}
Some other class (even in another project) can take that person and pass it to the persistence layer:
public void SavePerson(Person person)
{
database.Save(person);
}
So if I want to add a State to the person I just change the Address class and I'm all done in one step, I don't have to add the state field to all the method parameter lists:
public class Address
{
public string Street { get; set; }
public string City { get; set; }
// this is the new property
public string State { get; set; }
}
Create a model object that has a value for each control.
So let's say you have a form that has a first name, last name, birthday and salary.
Your model would be
public class SalaryModel
{
public string FirstName {get; set;}
public string LastName {get; set;}
public DateTime Birthday {get; set;}
public decimal Salary {get; set;}
}
Then when submit is clicked, you create this object and pass it to your generator class.
One reason for this is your generator needs to know NOTHING about the control other than it's value. That is a generator class shouldn't be concerned about .IsVisible() or .TabOrder or any of that other junk. It only cares about what the value is.
Create a container class. Keep an instance of it common for your main form and whatever form is going to use it/pass it to the other form or class as parameter.
Take all the values from your form and fill the container class. Usually a container/entity class would be full of properties and will have a very few methods.
Move you Generate() Method to a class and utilize the class properties. You can also then support data binding from you form.
Ex.
Take this
Generate (List<int> x, bool Opt1);
to This
public class Generate
{
List<int> Ids {get;set;}
bool Opt1 {get;set;}
bool Generate();
}

Class encapsulation with Repository Pattern

I am sortof using a repository pattern to extract information from a database. I have two classes, report and reportRepository.
The trouble I have is that since reportReposity has to fill in all the details for the report object, all the members in the report have to be publicly accessible.
Is there a way so that I can ensure that only the repository class can access some of the methods of the report class and only it can set some of the properties that other classes cannot, sort of like what friend does in c++. Or is there a completely different way of handling this situation?
I am using C# in ASP.NET 2.0
This looks a bit funky but it does what your after, any property with a 'protected' modifier will only be accessable within that class AND any derived classes
public class Person
{
public string Name { get; protected set; }
public int Age { get; protected set; }
}
public class PersonRepository
{
public Person Get()
{
return new PersonBuilder("TestName", 25);
}
private class PersonBuilder : Person
{
public PersonBuilder(string name, int age)
{
this.Name = name;
this.Age = age;
}
}
}
So unless your within the repository you can't see the Person derived class PersonBuilder which has a constructor that populates the protected properties of Person. Externally it looks like your magically populating fields without using setters or constructors.
You can apply access modifiers to properties, e.g:
public string Name { get; internal set; }
Internal gives write access to the specified property for any types in the same assembly.

Categories