Let's say I have the following two classes:
public class Person
{
public string Name { get; set; }
public string Address { get; set; }
}
public class Customer: Person
{
public string CustomerNumber { get; set; }
public string PaymentTerms { get; set; }
}
Now, if I have a person that I want to make a customer, I have, to the best of my knowledge, three options, and I'm hoping for advice on which is the best and on any other options, maybe using the new dynamics stuff in C#4.
I can add a constructor or property to Customer that takes a Person and assigns values to the base class, e.g.
public Customer(Person person)
{
base.Name = person.Name;
base.Address = person.Address;
}
or I can implement an untidy set accessor like this:
public Person Person
{
set
{
Name = value.Name;
Address = value.Address;
}
}
or I can aggregate Person into Customer like this:
public class Customer
{
public Person Person { get; set; }
public string CustomerNumber { get; set; }
public string PaymentTerms { get; set; }
}
The last is to me the neatest, except for always having to e.g. access Customer.Person.Name, instead of just Customer.Name.
I would personally go for composition, yes (your last option). Note that you can always provide "helper properties":
public string Name { get { return Person.Name; } }
Indeed, you can do this for all the properties you want, and never expose the Person property to the outside world at all.
On the other hand, inheritance is useful if you want to be able to treat a Customer as a Person - passing it to methods with a Person parameter, for example. I usually accomplish that sort of thing with interfaces though; you could have an IPerson interface implemented by both Customer and Person. Inheritance introduces all sorts of design decisions which simply don't come up (or are a lot simpler) when you don't get into inheritance.
I'd either use the constructor, or maybe a factory method, like
public static Customer CreateFromPerson(Person person)
{
return new Customer(){ Name = person.Name }//etc...
}
I don't like the setter as you're not actually setting the 'Person' on a customer, and I don't like the last option because it leads to a Law of Demeter (LOD) violation when you access the person through the customer (customer.person.name etc).
Related
I am experimenting with classes and was wondering if it is possible to link classes depending on a boolean value within one of the classes. I have a Person class and a field is private 'boolean value HasPet'. So if a person has a pet then I would like for a pet object to be made and link the classes together. Is this possible. I am completely new to classes. Would I have to make an ID field and link them like that?
static void Main(string[] args)
{
Person Teacher = new Person("Phoebe", 32, "brown", "hazel", true);
}
public class Person
{
private string Name;
private int Age;
private string HairColour;
private string EyeColour;
private bool HasPet;
public Person(string name, int age, string hairColour, string eyeColour, bool hasPet)
{
Name = name;
Age = age;
HairColour = hairColour;
EyeColour = eyeColour;
HasPet = hasPet;
}
public void ChangePetStatus()
{
Console.Write($"We heard that your pet status has changed...");
if (HasPet == true)
{
Console.WriteLine("we are sorry to hear that. Pet status has been changed.");
HasPet = false;
}
else
{
Console.WriteLine("that's great. A pet is a lovely addition to the household. Pet status has been changed.");
HasPet = true;
}
}
public void Greetings()
{
Console.WriteLine($"Hello my name is {Name} and I am {Age} years old. I have {HairColour} hair and {EyeColour} eyes. It is {HasPet} that I have a pet.");
}
}
My suggestion would be to reevaluate what inheritance means, if we look into Microsoft's definition
Inheritance is one of the fundamental attributes of object-oriented
programming. It allows you to define a child class that reuses
(inherits), extends, or modifies the behavior of a parent class. The
class whose members are inherited is called the base class. The class
that inherits the members of the base class is called the derived
class.
In your case I would say that inheritance has nothing to do with Person and the referred Pet class as neither of them will be inheriting or reusing each other's members, if you or the task insists on using inheritance for this case you'll need some other class that groups Person and Pet by similar properties for example LivingBeing which could have functions Respire(), Move() etc..
I would say make a many to many relationship(or one to many, if it's a specific case and Pet can't have more than one Person as owner), where Person could have many Pets and Pet could have many Persons as owners.
classes which I would suggest are:
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public string HairColour { get; set; }
public string EyeColour { get; set; }
public IEnumerable<PersonPet> PersonPets { get; set; }
}
public class PersonPet
{
public int PersonId { get; set; }
public int PetId { get; set; }
}
public class Pet
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
public IEnumerable<PersonPet> PetPersons { get; set; }
}
Where you would not need any inheritance or HasPet field as you can determine whether Person has a Pet or not by PersonPets.
EDIT:
As suggested in subcomments by #Ralf this is a relational view on current problem and classes could be subject to change. The main point is that, to link Person and Pet, using inheritance is not a right way. At least in the context which author provided
There is an abstract class Subject which has 2 derived classes: Company and Person. Both have shared members like name or address as well as not shared properties unique to each. Let's say the Company has a property int employeesNumber, while person has a property string insuranceID. Now, since both Company and Person are supposed to work in the same pipeline (being stored in lists, seinding data to userforms etc), those "odd" properties are the cause of my problems. Here's what I tried to do:
first I make a base abstract class Subject which has the shared name and address properties as well as an interface IOtherProps for the odd properties. Even though the classes, implementing the interface share no properties by design, and therefore the interface is a blank, I used it so only few classes could be valid to implement it.
public abstract class subject
{
public string name { get; set; }
public string address { get; set; }
public IOtherProps otherprops;
}
public interface IOtherProps
{
}
Next, we have Company and Person derived classes, each implementing PropsCompany and PropsPerson classses respectively through IOtherProps to store the class specific data:
public class Company : Subject
{
public Company()
{
otherprops = new PropsCompany();
}
}
public class Person : Subject
{
public Person()
{
otherprops = new PropsPerson();
}
}
public class PropsCompany : IOtherProps
{
public int employeesNumber { get; set; }
}
public class PropsPerson : IOtherProps
{
public string insuranceID { get; set; }
}
Now let's try to initialize an object:
static void Main(string[] args)
{
Person person = new Person()
{
name = "John Smith", //ok
otherprops = { insuranceID = "12345" } // CS0117 C# \
//"IOtherProps" doesn't contain definition for "insuranceID".
};
}
C# won't let me initialize a nested class that only get initialized in the Person() constructor. The linter won't even give me a prompt on the members of otherprops and I might not remember which class contains which odd properties.
So I tried to override the otherprops in the Person class, got another error:
public class Person : Subject
{
public Person()
{
}
public override PropsPerson otherprops = new PropsPerson();// CS0106 C# The modifier
//'modifier' is not valid for this item
}
So, my question is: how do I initialize insuranceId in this example? And more general question: is my solution of handling the "odd" data like that is generally correct or am I missing something?
otherProps is defined on the subject base class as IOtherProps, which does not contain insuranceID.
Furthermore, you cannot override a field. If it was a property you could declare it virtual to solve CS0117, but you cannot override a property with a different type.
You need to declare subject as a generic type, and declare the field/property as that type:
public abstract class subject<TOtherProps> where TOtherProps : IOtherProps
{
public string name { get; set; }
public string address { get; set; }
public TOtherProps otherprops {get; set;} // or you could leave it as a field
}
Then Person can be declared like so:
public class Person : Subject<PropsPerson>
Now, the type of otherprops is statically known to be PropsPerson, which also implements IOtherProps.
Instead of the IOtherProps interface, I would just add the other properties unique to the Person and Company classes directly in those classes.
public abstract class Subject
{
public string Name { get; set; }
public string Address { get; set; }
}
public class Person : Subject
{
public Person()
{
public string InsuranceID { get; set; }
}
}
This is the more common implementation for multiple concrete implementations of an abstract class and easily allows you to do exactly what you want.
static void Main(string[] args)
{
Person person = new Person()
{
Name = "John Smith",
InsuranceID = "12345"
};
}
The only thing you lose the supposed protection of only a few classes being able to implement it but I'm not sure how effective that would be anyway.
I have a class Person (Parent class) which contains some properties. Let's say 2 properties. I want to access 1 properties out of 2 properties in Student (child class) from Person class(Parent class).
Note: All properties are public which I need to use in other child class.
How will I achieve that using C#? (This applies to any object oriented programming languages)
Below is my sample code.
using System;
public class Person
{
public string name; //only want this property in all child classes
public float salary; //don't want to access this property in Student
}
public class Student: Person
{
public string subject;
}
public class Employee: Person
{
public int employeeId;
}
You shouldn't have salary as a field in Person unless all Persons have a salary,
this should instead go in the Employee class, or the highest class which uses salary
There is a conceptual problem in your code! The salary property is not general enough to be in the person class (not every person has a salary). You should not include this property in the Person class.
Using an interface would help only if:
you have multiple subclasses and some of them have salaries
you need to manage the subclasses that have salaries as a group without knowing the particular type of each one (e.g. polymorphism).
Hope that helps!
You can use an interface to achieve what you are aiming for. It doesn't stop the compiler from creating a Salary property for student object. But by using IStudent, you can restrict the access of the end user.
public class Person
{
public string Name { get; set; } //only want this property in all child classes
public float Salary { get; set; } //don't want to access this property in Student
}
interface IStudent
{
string Name { get; set; }
string Subject { get; set; }
}
public class Employee : Person
{
public int EmployeeId { get; set; }
}
public class Student : Person, IStudent
{
public string Subject { get; set; }
}
class Program
{
static void Main(string[] args)
{
IStudent s = new Student() { Name = "Student1", Subject = "Subject1" };
Console.WriteLine(s.Name);
}
}
I'm having some weird problems here with a Class that I've written. I cannot access anything inside of Account, unless I access it directly from Account.Whatever.
I'd like to be able to do:
Account account = new Account();
account.Name...
but I can't. Nothing shows up in intellisense. I can only access things if I do:
Account. - for example, Account.AccountHolder...
class Account
{
class AccountHolder
{
enum Salutation
{
Mr,
Mrs,
Ms,
Miss,
Dr,
Hon
}
struct Name
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}
enum Sex
{
Male,
Female
}
}
}
I don't understand what's going on. Note, that I have also tried every possible combination of things but something is very wrong here. I've tried adding public to my Account class. I've tried adding public to my AccountHolder class. I've tried using public static etc etc etc.
I've never had this problem before. And why am I experiencing this same problem no matter how much I change it around?
The Account class is in an Account.cs file inside the same winforms project.
One real question might be: Why do you need Nested Types here at all?
Nested types are especially used when no other types cannot reuse a type of your parent type, that is, if your nested type shall expose properties or values only applicable to your parent type. Otherwise it is mostly best to create independant types.
To me, it looks reasonable to think that you might use the Salutation enumeration outside of the AccountHolder class, as an Account Holder is nothing more than a legal entity, that is, a real person or a company.
If your system could use Salutation elsewhere, than it is best to create the enumeration per itself, in its own file, and expose a property out of your AccountHolder class.
Salutation
public enum Salutation {
Mr
, Mrs
, Ms
, Miss
, Dr
, Hon
}
AccountHolder
public class AccountHolder {
public Salutation Salutation { get; set; }
// ...
}
In the later, one might also be insterested to know what's an account holder at once?
Might it be a company, a person, a customer, a supplier, or else?
Then perhaps shall you consider to define a hierarchy of account holders and make it a property of the most general class type.
LegalEntity
public class LegalEntity {
public string Name { get; set; }
}
Company
public class Company : LegalEntity {
// Some members specific to a Company here...
}
Person
public class Person : LegalEntity {
public Salutation Salutation { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get { return base.Name; } set { base.Name = value; } }
// Some other members specific to a person here...
}
Then, you have your Account class
public class Account {
public LegalEntity AccountHolder { get; set; }
}
So my point is that there is no use of Nested Types here, depending on your needs, which I'm not actually aware, obviously. And it turns out that an AccountHolder may now be of any types deriving from LegalEntity. Later on, when there is a need for another type of AccountHolder, you may simply derive from LegalEntity, or any other types which actually derives from it to make it an AccountHolder, as an AccountHolder is simply a property of an Account, and not a class per itself.
Some examples of using Nested Types adequately:
Why Would I Ever Need to Use C# Nested Classes
Why/when should you use nested classes in .net? Or shouldn't you?
Furthermore, you will need to make your Nested Types public in order to access them from outside of your class. This doesn't mean that will be able to avoid the Parent.NestedType nomenclature, you will not.
Apart from it, I see no problem in your code. Nested Types are by definition hidden somehow within another type. So when you wish to access them, you always need to type in the parent name which contains the type you need to access.
Plus, once you can access the Nested Type, you will be obliged to create members into your Account class to holde references to your instances of those Nested Types. IMHO, there is no gain of using them here. But hey, I insist, I'm not aware of your reality and the choices behind your design.
You are trying to access nested class, struct, enum. It should be done with the nesting class name, e.g. Account.Name.
But if you have
class Account
{
public struct Name
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
}
public Name MyName {get; set;}
}
then you may access the MyName property using the instance of Account class.
This is how the language works.
What you are probably wanting to use here are namespaces. Any nested class will always have to be fully qualified with its parent classes to be used. If you use a namespace, anything within that namespace can be used together without fully-qualifying, and can be used outside the namespace (within the bounds of access modifiers) by either fully-qualifying or by inserting a using directive (using Accounting; in this case).
Also, are you sure you want to be using a struct? Value types are immutable, so if you change any member of that struct, you're always creating an entirely new instance of the struct (generally significantly less efficient).
namespace Accounting
{
class Account
{
public PersonName Name { get; set; }
public Sexes Sex { get; set; }
public Salutations Salutation { get; set; }
}
class PersonName
{
public string First { get;set; }
public string Middle { get; set; }
public string Last { get; set; }
}
enum Salutations : byte
{
Mr,
Mrs,
Ms,
Miss,
Dr,
Hon
}
enum Sexes : byte
{
Male,
Female
}
}
If I have created the following Employee object (simplified)...
public class Employee
{
public Employee()
{
}
public String StaffID { get; set; }
public String Forename { get; set; }
public String Surname { get; set; }
}
... would it be acceptable to have another property in the Employee object with a Type also being Employee to hold their Manager's details (as shown below)?
public class Employee
{
public Employee()
{
}
public String StaffID { get; set; }
public String Forename { get; set; }
public String Surname { get; set; }
public Employee Manager { get; set; }
}
Also, what is the best way to instantiate the Employee object for the Manager property? Obviously including this.Manager = new Employee(); in the constructor will cause an infinite loop. Would a Manager class that inherrits from Employee be the best way (even though all the properties would be identical)?
An object can indeed have a reference to an object of its own type.
This is how most Node type objects are implemented.
As for instantiation - you can pass in the Employee object to use as manager (passing in null for no manager). Constructors can have multiple overloads:
public Employee(Employee manager)
{
this.Manager = manager;
}
Yes, an object can contain references to other objects of the same class.
And secondly, I wouldn't create a new Employee in the cunstructor but inject it like this:
public class Employee
{
public Employee(Employee manager)
{
this.Manager = manager;
}
public String StaffID { get; set; }
public String Forename { get; set; }
public String Surname { get; set; }
public Employee Manager { get; set; }
}
The only scenario where this isn't possible is with a struct; a struct is contained directly (rather than being a fixed-size reference to the data), so the size of an Employee struct would have to be "the size of the other fields plus the size of an Employee", which is circular.
In particular you can't have:
struct Foo {
Foo foo;
}
(or anything else that would result in a circular size) - the compiler responds with:
Struct member 'Foo.foo' of type 'Foo' causes a cycle in the struct layout
However, in all other cases it is fine; with the issue of initialisation, I'd say: just leave it unassigned initially, and let the caller assign a value via the property.
First, the answer is Yes an object can have a field that contains an instance of itself. It can even have methods that accept or return the instances of the same class, and it can even depend on itself in the definition of the class, e.g:
public class Person : IComparable<Person> //legal, recursive definition
{
//fields (or properties) that are of type Person
public Person Father;
public Person Mother;
public List<Person> Children;
// method that takes a Person as a parameter
public bool IsParent(Person potentialParent)
{
....
}
//method that returs a Person
public Person Clone()
{
//TODO: real implementation coming soon
}
public Person(){}
//constructor that takes persons as arguments
public Person(Person father, Person Mother)
{
Father = father;
Mother = mother;
}
}
By default all reference values are null'd so you won't have a constructor problem unless you create one yourself. So, Yes, there can be some issues with circular references and endless loops (each parent has children that have children that have parents etc...) but usually they can be trivially detected and avoided.
The only times I've encountered these kind of problems is when I used XML (or other text-based) serialization on circularly referenced objects.
Yes, you can have Employee inside Employee and it will not cause infinite loop, by default Manager property of Employee object will be null.
It works, you can just try s.th. like:
public class A
{
public A test { get; set; }
}
Specifically on the issue of construction (I've +1'd Odeds answer) - as you say constructing an instance in the constructor is a bad move.
But then ask yourself - why would you ever need to anyway. In your Manager/Employee case - you can't always be sure that an employee always has a manager, and if they don't then you shouldn't be using a newed empty instance to signify that, but a null.
When your type will have public get/set accessors on the properties, generally you're likely to be loading these object trees from some external source, in which case you have nothing to worry about. Equally, you can have a constructor that accepts other Employee instances for Manager/Employee relationships etc.
You should also be checking for circular relationships in that constructor as well - i.e. an employee can't be someone's manager and their employee - try walking the child->parent relationship for that and see if it ever ends!
I tried this way and it worked for me:
class Program
{
static void Main(string[] args)
{
A a = new A(new A());
}
}
public class A
{
public string Name { get; set; }
public A a;
public A() { }
public A(A _a)
{
a = _a;
}
}
Now you can use it in the Main() function like:
class Program
{
static void Main(string[] args)
{
A a = new A(new A());
a.Name = "Roger";
a.a.Name = "John";
Console.WriteLine("{0}, {1}", a.Name, a.a.Name);
}
}