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
Related
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 have a question regarding OOP composition.
Let's say that a mother has 0 or plus children, and a child has one and only one biologic mother.
To illustrate it, I did the following :
public class Mother : ObservableObject
{
// [...]
ObservableCollection<Child> Children {get; set;}
}
public class Child : ObservableObject
{
public Child(Mother mother)
{
this.Mother = mother;
// Adding the child to the mother's children collection
mother.Children.Add(this);
}
public Mother Mother {get; set;}
}
but I wonder if it's okay to automatically add the child to the mother's collection, or if I should go with the following :
Mother mother = new Mother();
Child child = new Child(mother);
mother.Children.Add(child);
Thanks :)
I'd prefer,
public class Mother : ObservableObject
{
// ...
public Child GiveBirth()
{
var newBorn = new Child(this);
this.Children.Add(newBorn);
return newBorn;
}
// ...
}
I think the modeling is a little off. A Mother and a Child are semantically related to one another, but they're instances of the same object. They are both a Person.
The creation of a Person is an operation performed by a Person. So a Person shouldn't even have a public constructor, but rather a factory method which takes care of this logic. Something like this:
public class Person : ObservableObject
{
private Person()
{
Children = new ObservableCollection<Person>();
}
public Person Mother { get; private set; }
public ObservableCollection<Person> Children { get; private set; }
public Person Procreate()
{
var child = new Person();
child.Mother = this;
this.Children.Add(child);
return child;
}
}
This modeling is still a bit limited, for example we're only talking about asexual reproduction here. So we're not effectively modeling humans yet. Perhaps we need to add a father?
public class Person : ObservableObject
{
private Person()
{
Children = new ObservableCollection<Person>();
}
public Person Mother { get; private set; }
public Person Father { get; private set; }
public ObservableCollection<Person> Children { get; private set; }
public Person Procreate(Person father)
{
var child = new Person();
child.Mother = this;
child.Father = father;
this.Children.Add(child);
father.Children.Add(child);
return child;
}
}
We'll want to add some checking for nulls and whatnot of course. Now we've also discovered that we need to specify genders. (While family structures may vary considerably, the act of creating a person is pretty well established.) So we can keep adding features like that. At some point we may indeed subclass these, but those subclasses will likely end up being mostly semantic pass-through objects with hard-coded default values for this Person superclass.
But just for fun, let's try adding genders...
public class Person : ObservableObject
{
private Person(Sex gender, Person mother, Person father)
{
// TODO: Check for null mother and father
this.Gender = gender;
this.Mother = mother;
this.Father = father;
Children = new ObservableCollection<Person>();
}
public Sex Gender { get; private set; }
public Person Mother { get; private set; }
public Person Father { get; private set; }
public ObservableCollection<Person> Children { get; private set; }
public Person Procreate(Person father)
{
// TODO: Check for null father, confirm gender of father
var child = new Person(PickRandomGender(), this, father);
this.Children.Add(child);
father.Children.Add(child);
return child;
}
private Sex PickRandomGender() { /.../ }
public enum Sex
{
Female,
Male
}
}
Ok, that was fun. Cleaned up a little bit by moving some logic to the constructor as well. But now there's another problem... fathers can procreate. Which sounds kind of painful. Now it looks like we're ready to subclass:
public class Person : ObservableObject
{
protected Person(Sex gender, Person mother, Person father)
{
// TODO: Check for null mother and father
this.Gender = gender;
this.Mother = mother;
this.Father = father;
Children = new ObservableCollection<Person>();
}
public Sex Gender { get; private set; }
public Person Mother { get; private set; }
public Person Father { get; private set; }
public ObservableCollection<Person> Children { get; private set; }
protected Sex PickRandomGender() { /.../ }
public enum Sex
{
Female,
Male
}
}
public class Woman : Person
{
// TODO: Override Gender with a hard-coded value
public Person Procreate(Person father)
{
// TODO: Check for null father, confirm gender of father
var child = new Person(PickRandomGender(), this, father);
this.Children.Add(child);
father.Children.Add(child);
return child;
}
}
(Should we subclass a Man as well? It semantically seems cleaner, but are there any operations or attributes specific to men that aren't shared by women? Perhaps, but our models aren't that detailed yet.)
Looking back, the classes of Mother and Child seem kind of limited and short-sighted at this point. A woman isn't necessarily a mother, and all people are children. As you can imagine, there are plenty of features to add to this system. But following the same general process of building out the domain like this should accommodate that.
Suppose you have a class name building. This class building has a function called BuildRooms(). There is another class Room having functions to make rooms. You create objects of class Room as r1, r2,r3 etc. Now this building has 3 rooms. We can open doors and close doors methods inside Room class. Building class is composed of Rooms. It means this building has 3 rooms. Write code in any language you prefer. This is composition. Building has rooms so it is Has-A relationship.
class building{
void make_rooms()
{
room r1=new room(), r2=new room();
r1.open();
r2.close();
}
}
class room{
void open()
{
}
void close()
{
}
}
I'm sorry if it's a dumb question, but i just can't seem to get a grip.
I got 2 classes, Customer and Member.
Customer.cs
public class Customer
{
public virtual string Firstname { get; set; }
public virtual string Middlename { get; set; }
public virtual string Lastname { get; set; }
}
Member.cs
public class Member : Customer
{
public virtual string MemberId { get; set; }
public virtual string MemberRegistrationDate { get; set; }
public virtual string MembershipStatus { get; set; }
public Member()
{
MemberRegistrationDate = DateTime.Now;
MembershipStatus = MembershipStatusEnum.Active;
}
}
I'm pretty sure this has to be an inheritance, in which Member is a Customer, though if I'm being desperate I can resort to composition.
Note that here I'm using NHibernate that forces me to use all that virtuals.
Given a single customer object, how should a new Member from an existing Customer ?
I can think of 2 options here :
1 - Using Member.cs constructors to recreate it's parents properties
Is this a good thing to do? I tried to do this :
public class Member : Customer
{
public virtual string MemberId { get; set; }
public virtual string MemberRegistrationDate { get; set; }
public virtual string MembershipStatus { get; set; }
public Member(Customer customer)
{
Firstname = customer.Firstname;
Middlename = customer.Middlename;
Lastname = customer.Lastname;
MemberRegistrationDate = DateTime.Now;
MembershipStatus = MembershipStatusEnum.Active;
}
}
But Resharper warns me about accessing virtual member in a constructor, which I do agree to avoid, and tells me to make Member a sealed class which cannot have virtual members (no NHibernate compatibility).
It also raises another issue when someday I added a new property to Customer class, and I forgot to do the same to Member constructor.
2 - Using some sort of reflection helper to map between two objects.
Sure it's a viable option, but I'm currently learning about DDD and I'm wondering if it's okay to put such helper in the domain layer?
Need some suggestions, thanks !
Not sure if I get you right, but there's no need to do anything Customer related in your Member class. You only need to tell NHibernate that Member derives from Customer, and you need to provide the correct mapping for both classes. That's it, the rest goes automatically (that's the whole point of inheritance in OOP, anyway).
Regarding your second issue ('Don't call virtuals in c'tor.'): That's theoretically true, but only relevant if there's a chance that the virtual method gets overwritten in a derived class. So you could safely ignore the R# warning here.
But I think it's cleanest here to get rid of the Member c'tor altogether and declare the class like so:
public class Member : Customer
{
private memberRegistrationDate = DateTime.Now;
private membershipStatus = MembershipStatusEnum.Active;
public virtual string MemberId { get; set; }
public virtual string MemberRegistrationDate
{
get { return this.memberRegistrationDate; };
set { this.memberRegistrationDate = value; };
}
public virtual string MembershipStatus
{
get { return this.membershipStatus; };
set { this.membershipStatus = value; };
}
}
EDIT:
If you're looking for an easy way to turn a customer, into a member, you should maybe entirely keep the conversion code away from your classes and put it into an extension method instead (to keep things clean):
public static class CustomerExtensions
{
public static Member ToMember(this Customer customer)
{
var member = new Member();
member.Firstname = customer.Firstname;
member.Middlename = customer.Middlename;
member.Lastname = customer.Lastname;
return member;
}
}
You can call it then like this:
Member member = customer.ToMember();
I want to propagate the property from child class to parent class,
ie: If MySchool.ModifiedTime is changed it should change the ModifiedTime in Student Class too, like wise LstBook[0].ModifiedTime is changed it should change MySchool.ModifiedTime as well Student.ModifiedTime... (basically ModifiedTime should be in sync),any Idea
I'm looking for a Generic function in BaseClass to achieve this.
public class MyBaseClass
{
public DateTime ModifiedTime{ get; set; }
}
public class Student: MyBaseClass
{
public string Name { get; set; }
public school MySchool {get;set;}
}
public class School : MyBaseClass
{
public string SchoolName { get; set; }
public List<Book> LstBook {get;set;}
}
public class Book:MyBaseClass
{
public string BookName{get;set;}
}
You could make ModifiedTime virtual and then in each child class override it to perform the syncing.
public class MyBaseClass
{
public virtual DateTime ModifiedTime{ get; set; }
}
public class Student: MyBaseClass
{
public string Name { get; set; }
public school MySchool {get;set;}
public virtual DateTime ModifiedTime
{
get {
return MySchool.ModifiedTime;
}
set {
MySchool.ModifiedTime = value;
}
}
}
And so on.
However, I would reconsider your class hierarchy because it seems like the factoring is incorrect. If all the properties need to be in sync across the entire hierarchy then maybe only one class should have that property and other classes should refere to it. For example, only School should have the ModifiedTime property and when you need to get the modified time for a student you would retrieve it through the MySchool property
You seem to be misunderstanding how object hierarchy works.
Implementing this as a class member only links it to the object created, and a static method would of course mean all objects access the same property.
Instead, as I understand it, you want groups of instances (not all) to share a property.
The simplest way to do this is to create a shared object that provides the modified time for all instances in a group.
As the other commenters have pointed out, you can't do this in a straightforward way with a base class simply because that's not how class hierarchies work. What you could do is create another class called "GroupInfo" or something like that. Make ModifiedTime a property on that.
In all your other classes, add a property for a GroupInfo. Then whenever you create a new book or whatever, as part of the constructor pass in a reference to the GroupInfo for the book.
That way all the objects in the group will share a single GroupInfo, and thus a single ModifiedTime.
You can make ModifiedTime static, which will cause it to be shared among all derived instances of MyBaseClass.
public class MyBaseClass
{
public static DateTime ModifiedTime{ get; set; }
}
Update: More complete example; better explanation of methodology
Your base class could be better described as a interface since your enforcing that each class implement a common property and not making common calculations or sweeping generalizations that could group schools, students, and books together.
Pursuing an event driven solution there are a few things you can do such as using BindingList<T> which is basically List<T> on steroids.
Unfortunatly, you'll need to explode your pretty little { get; set; } properties into full fields, but the best way is for each modification of a property to trigger an event. Each subsequent object that is affected by the modification is subscribed to your modified objects Modified event.
public interface IChangeAware
{
event EventHandler<EventArgs> OnChange;
DateTime ModifiedTime { get; set; }
}
public class Student : IChangeAware
{
public event EventHandler<EventArgs> OnChange;
public DateTime ModifiedTime { get; set; }
public string Name { get; set; }
public School School
{
get { return School; }
set
{
School = value;
if (this.OnChange != null)
this.OnChange(this, new EventArgs());
}
}
public Student()
{
if (School != null)
School.OnChange += MySchoolOnChange;
}
void MySchoolOnChange(object sender, EventArgs e)
{
ModifiedTime = DateTime.Now;
}
}
public class School : IChangeAware
{
public event EventHandler<EventArgs> OnChange;
public DateTime ModifiedTime { get; set; }
public string SchoolName { get; set; }
public BindingList<Book> Books { get; set; }
public School()
{
Books = new BindingList<Book>();
Books.ListChanged += BooksListChanged;
}
void BooksListChanged(object sender, ListChangedEventArgs e)
{
ModifiedTime = DateTime.Now;
OnChange(this, new EventArgs());
}
}
public class Book
{
public string BookName { get; set; }
}