Initializing a nested member with properties unknown in advance - c#

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.

Related

Can I selectively inherit a class depending upon a boolean field?

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

How to access some properties (not all) of parent class in child class?

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

How can I define a static instance of an abstract class?

I'm working with an abstract class in C# being inherited by multiple classes. One of the things I've been needing in my code is a static property such as "Unset", which would be a static instance of the class with it's main properties defined to an unset value. A generic example is as follows:
public abstract class Person
{
public string Name {get; set;}
public string PhoneNumber {get; set;}
public static readonly Person Unset = new Person() {
Name = "Unset Name"
PhoneNumber = "Unset Phone"
}
}
However I can't construct the "Unset" property because Person is an abstract class. I don't want to define the property for every class that derives from "Person". Is there a way to work around this?
You can't create an instance of an abstract class.
What you can do, however, is create a new child:
public class UnsetPerson : Person
{
public UnsetPerson() : base()
{
this.Name = "Unset Name";
this.PhoneNumber = "Unset Phone";
}
}
And then set the static property on your base class:
public abstract class Person
{
public string Name { get; set; }
public string PhoneNumber { get; set; }
public static readonly Person Unset = new UnsetPerson();
}
The documentation shows that the abstract keyword indicates that the thing being modified has a missing or incomplete implementation. As a result, it cannot be directly created, and can only be used through inheritance.
Since you don't (currently) have any abstract members in your abstract class, you could instead go with a virtual class, which allows you to provide a default implementation that can be optionally overwritten.
public virtual class Person
{
public virtual string Name { get; set; }
public virtual string PhoneNumber { get; set; }
public static readonly Person Unset = new Person() {
Name = "Unset Name",
PhoneNumber = "Unset Phone"
};
}
If you don't need/want to override any of the class members in an inheriting class, you don't need to make an abstract or virtual class. Any (non-sealed) class can be inherited.
I don't fully understand your requirements. Do you want to make sure that a freshly created instance of a derived class has those "unset" values? That could be done with a constructor in the abstract class:
protected Person()
{
Name = "Unset Name";
PhoneNumber = "Unset Phone";
}
Yes, an abstract class can have a constructor, even though you cannot instantiate it directly. The constructor of a base class is called before the constructor of a derived class, so that you can overwrite those "unset" values in the constructor of a derived class whenever it has appropriate parameters.

Can a Custom C# object contain a property of the same type as itself?

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

Aggregation versus Inheritence in C#, or alternatives

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

Categories

Resources