I'm currently looking into inheritance and polymorphism and I'm a bit confused about where you'd want to create a Person object of type Student?
assuming the following code:
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Gender { get; set; }
}
class Student : Person
{
public int YearOfStudy { get; set; }
public string Course { get; set; }
public string PredictedGrade { get; set; }
}
Now looking online, there are a few options here in terms of creating an object:
Person p = new Person();
Student s = new Student();
Person ps = new Student();
The first objects allows me to set name, age and gender, while the second allows me to set those 3, as well as yearsOfStudy, course and predictedGrade. But I'm unsure of what the third object allows me to do? I can still set all 6 parameters, however I can only use the attributes set in the Person class? Any explanation on the correct usage of the third object would be appreciated.
Thanks
Don't think of this as Person ps = new Student() yet.
The real benefit is being able to abstract common code for all types of Person. So your methods may take in a Person because that's all it needs and will work with any person type you create such as Janitor, Teacher, etc.
var myStudent = new Student()
VerifyAge(myStudent);
VerifyYearOfStudy(myStudent);
public bool VerifyAge(Person person)
{
return person.Age < 200;
}
public bool VerifyYearOfStudy(Student student)
{
return student.YearOfStudy <= DateTime.Now.Year;
}
To clear up some confusion the only time you ever really declare the base in a method is when you want to actually denote that this variable is only meant to be used as that specific type. Think of it as if you had declared your variable using an interface instead. Sure I am working with a Student instance, but I am only working with it as a Person instance or as IPerson.
Normally as a variable in a method you wouldn't do that because pretty much the defacto standard is to just use var for everything nowadays. Where you do make the choice to define Person is normally on properties, method return values, and method parameters. Local variable is not really important.
Because Student class is derived from Person class, any Student object is also a Person object. Thus a notation Person ps = new Student(); means we're declaring variable ps to be of type Person and instantiate it as Student. It could be used if you have a method that takes Person object as parameter, e.g.
public void Foo(Person p) { if(p.Age > 21) Console.WriteLine("OK to drink!"); }
However, if you have a method that operates on properties of derived class you must declare and instantiate the instance of it. So for
public void Foo(Student s) {if(s.YearOfStudy == 1) Console.WriteLine("Freshman"); }
you must use Student s = new Student();.
Related
Let's say I have an ObservableCollection<Person>.
Now, every student can have some sort of opinion on every other person. What would be the best way to code something like this, so that it's accessible from both objects?
I thought about something like this for a relations:
enum RelationPoint { Neutral, Like, Dislike, Love, Hate }
List<RelationPoint> relation;
How can I define something like this for every person?
You could create an object, which stores the opinion in an object, like this:
public class Opinion
{
public Person Destination
{
get;
set;
}
public Person Target
{
get;
set;
}
public RelationPoint RelationType
{
get;
set;
}
}
If you store them like this in a list, every person can have an opinion abount another pserson.
To figure out, which person has which optinion, you can simply find this out using linq:
var goodRelation = listOfOption.Where(item => item.RelationType == RelationPoint.Like && item.Destination = <<Some Person>>);
Now you know, which person the Destination likes.
One solution would be to make an object called "Relation" which contains 2 persons.
So you would have following classes:
public class Person
{
public String Name;
....
}
and a class "Relation:
public class Relation
{
private Person p1;
private Person p2;
private String opinion;
}
Now you could make sth. like this:
Person p = new Person ("John");
Person p2 = new Person ("David");
Relation r1 = new Relation(p, p2, "Neutral");
Just one of many solutions.
This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
I have my own Object, and I'd like to extend it, saving data from a person and adding new info.
So the code would be:
public class Student : Person
{
public string code { get; set; }
}
but when I try to init it and add the new value:
Person person = new Person("Paul", "Catch");
Student student = (Person)person;
student.code = "1234";
I got System.InvalidCastException: Unable to cast object of type 'MyLayer.Person' to type 'Student'.
Am I missing some point?
EDIT: maybe I wrong putting that Person class. You must suppose it become from a DB as object, such as Person person = new MyPersons().First();
So I won't to populate the new one with properties one by one, just extend one property thanks to the new object that extend the old one.
You cannot convert a Person to Student directly.
Inheritance in OOP comes with hierarchy level, i.e. you can cast the derived class to base class, but the opposite is not possible. You cannot cast base class to derived class
One possible solution is :
Create Student from Person using constructor overload.
public class Person
{
public string FName { get; set; }
public string LName { get; set; }
public Person(string fname, string lname)
{
FName = fname;
LName = lname;
}
}
public class Student : Person
{
public Student(Person person, string code)
: base(person.FName, person.LName)
{
this.code = code;
}
public Student(Person person)
: base(person.FName, person.LName)
{
}
public string code { get; set; }
}
static class Program
{
static void Main(string[] args)
{
Person person = new Person("Paul", "Catch");
// create new student from person using
Student student = new Student(person, "1234");
//or
Student student1 = new Student(person);
student1.code = "5678";
Console.WriteLine(student.code); // = 1234
Console.WriteLine(student1.code); // = 5678
}
}
Assign a Student to your Person.
Person person = new Student("Paul", "Catch");
Student student = (Student)person;
student.code = "1234";
Note that this makes all the casting pretty useless, better is:
Student student = new Student("Paul", "Catch");
student.code = "1234";
In your Student class, add this constructor, assuming you have a constructor that takes two strings in the Person class
public Student(string val1, string val2) : base(val1, val2) { }
then you can use it like this
Student student = new Student("Paul", "Catch");
student.code = "1234";
The problem you're seeing is that in your assignment, you're trying to downcast Person to Student. This isn't possible, because the object is a Person, and the Person type has no knowledge of Student.
My interpretation of it is that objects have a specific type, regardless of how you cast it. A cast (like the way light is cast on an object) just dictates how you see that object. In the example case, a Person has no knowledge of a Student, therefore no matter how you look at it, you can't assign it to student.
A Student object, however, can be upcast to a Person, since every Student is a Person. You can always upcast to base classes, but you can't always downcast to derived classes.
I hope this gives you some clarity. (I also hope I got this totally right.)
Your conversion is incorrect, a person can become a student (Not the other way round)
Change to:
Student student = (Student)person;
Although your type cast can be avoided ..
Person person = new Person("Paul", "Catch");
Student student = (Person)person;
student.code = "1234";
Becomes ....
Student student = new Student("Paul", "Catch");
student.code = "1234";
I have what seems to be a simple problem, but am unable to come up with a clean solution.
I have a two classes which looks like below
Class Person{
String name{get; set;}
int age{get; set;}
}
Class Alien{
String alienName{ get; set}
int alienAge{get; set;}
}
These classes are thirdparty classes that I have to use, have no control over. But at some point I would want to be able to construct a Alien object given a Person object and vice versa. I have only two properties in my example. In real life I may have upto 50 properties for both Alien and Person.
Alien is not a subset of Person and Person is not a subset of alien. Those are just two different objects. What do you guys think is the best way to transform these objects between each other. I don't want to laboriously write a copy method that takes in each property and sets its equivalent property in the other. Since the method names can be vastly different between those two classes, I don't think I might be able to use reflection either. Ideally am looking for something which would externalize the copy procedure so that if something changes in Alien or Person object in the future, I wouldn't have to change my logic.
Any suggestions?
Thanks
K
You might want to look at AutoMapper
Use Interfaces. If you have an Interface, certain properties that you must to be copied are already defined:
Interface ISubject
{
// properties
String name {get; set;}
int age {get; set;}
}
Class Person : ISubject
{
// contractors
public Person ()
{
...
}
public Person (ISubject subject)
{
name = subject.name;
age = subject.age;
}
...
}
Class Alien : ISubject
{
// contractors
public Alien ()
{
...
}
public Alien (ISubject subject)
{
name = subject.name;
age = subject.age;
}
...
}
and when you using:
var person = new Person();
...
ISubject subject = (ISubject) person;
var name = subject.name;
or
var person = new Person();
...
Alien subject = new Alien(person);
var name = alien.name;
You can try http://code.google.com/p/nutil/ , there is a class named BeanUtils, that have a method to copy properties.
Consider following method:
public PrintObjectHierarchy(object o)
{
Console.WriteLine(o.GetType.FullName);
object baseObject = PruneObjectToItsBaseObject(o);
if(!baseObject.GetType().Equals(typeof(object)))
PrintObjectHierarchy(baseObject);
else Console.WriteLine("System.Object");
}
For example if I wrote:
class Form1 : Form
{
static void Main()
{
Form1 f1 = new Form1();
PrintObjectHierarchy(f1);
}
}
Then it should print for me:
MyNamespace.Form1
System.Windows.Form
System.Windows.Forms.ContainerControl
/*and so so till...*/
System.Object
But unforunately, even if I CAST object to its BaseType, "C# Polymorphism" just will limit its VIEW to the base type and does not return a REAL reference from a REAL base object to me! Let's describe it by an example; if I have
class Person {
public string Name;
public string LastName;
}
class President : Person {
public string password;
}
main(){
President pr = new President() {Name="John"; LastName="Smith"; password="js123" };
Person p = (Person)pr;
SendToAirportSystemAcrossInternet(p);
}
While we think that p is a Person but it's not! it's the President and p is just a view from it, so the president's password will travel across the Internet!
Any idea about how to prune or slice an object to it's base to creating a real base object?
Thanks in advance!
Daniel's solution works; another similar approach would be to write an "copy constructor" and create a new person that way.
So, your person class becomes:
public class Person
{
public Person()
{
}
public Person(Person p)
{
this.name = p.name;
this.lastName = p.lastName
}
public string name;
public string lastName;
}
And you can create a person from a president like this:
President pres = new President() { name = "abc", lastName = "def", password = "kittens" };
Person p = new Person(pres);
This creates a person from a president but there is no way to get back to the president, and no way to get the password. If you create a person this was and cast to a president you will get an InvalidCastException, which I think is what you want.
It's not quite obvious what you're trying to achieve, but as you're interested in your object's inheritance hierarchy you'll most likely want to deal with instances of System.Type. Here's a working version of the first method you posted which might give you a hint on how to proceed from there:
static void PrintObjectHierarchy(object o)
{
Type t = o.GetType();
while (t != null)
{
Console.WriteLine(t.FullName);
t = t.BaseType;
}
}
Basically, you can't do what you want. You should redesign so that you don't have this requirement.
As I noted in comments, it may be that a set of fields in a base class is valid when the execution-time type is a derived class, but is invalid for an instance of just that class. Additionally, there may be all kinds of other safeguards which simply become invalid when an object is viewed in this way. For example, the base class may hold a reference to a collection of values, with the derived class expected to validate the values added to that collection. When the object is "pruned", that validation would be removed, but with a reference to the same collection as before:
// EvenNumbersOnlyCollection rejects odd numbers
EvenNumberCollection derived = new EvenNumbersOnlyCollection();
NumberCollection pruned = Prune<NumberCollection>(derived);
pruned.Add(5);
// This would return 5 - the invariant is broken!
int shouldBeEven = derived.First();
It's not clear why you think that this pruning would be a good idea, but you should try to achieve your wider goal in some other way.
When an object is created in C# is casted always to its original type. Even if you're using it as a base object or an interface, the call p.GetType() will always return the original type.
If you need to create a new object and then you need want to prune to its base object, you need to create a new object of type. For example:
public class ParentClass
{
public Parent(int feature1)
{
mFeature1 = feature1;
}
}
public class ChildClass : ParentClass
{
public ChildClass(int feature1, int feature2) : base(feature1)
{
mFeature2 = feature2;
}
}
...
...
ChildClass cc = new ChildClass(10, 20);
ParentClass pc = (ParentClass)cc; // pc still is of type ChildClass
ParentClass ccAsParent = new ParentClass(cc.Feature1); //ccAsParent is of type ParentClass
...
...
Remember that you can only do this if the parent class is not abstract.
I'm having a hard time figuring out how to implement a factory pattern in a DTO mapper I'm trying to create. I'm pretty sure I need to rethink my design. Here is a very small example of what I'm running in to:
public abstract class Person
{
public string Name { get; set; }
public decimal Salary { get; set; }
}
public class Employee : Person
{
public Employee()
{
this.Salary = 20000;
}
}
public class Pilot : Person
{
public string PilotNumber { get; set; }
public Pilot()
{
this.Salary = 50000;
}
}
public static class PersonFactory
{
public static Person CreatePerson(string typeOfPerson)
{
switch (typeOfPerson)
{
case "Employee":
return new Employee();
case "Pilot":
return new Pilot();
default:
return new Employee();
}
}
}
and to use the factory:
Person thePilot = PersonFactory.CreatePerson("Pilot");
((Pilot)thePilot).PilotNumber = "123ABC";
How do I get around loading the pilot number without typecasting it to Pilot?? is this the wrong way to do this? I could put the pilot number in the Person class, but then Employee would inherit the number and that's not what I want. What can I do?
Thanks!
-Jackson
The factory pattern is best used when the objects differ in implementation, not interface. In your case the factory pattern is not too beneficial, and you are probably better off creating your objects directly (or some other pattern maybe better).
You could add methods for specific types to your PersonFactory class, or add a generic CreatePerson<T>() method, but that would only be useful if the caller already knows what type of person it should be receiving. Maybe this is the case, or maybe not.
With this scenario, I'd expect that the code that is actually making the call to PersonFactory.CreatePerson would not know or care what kind of person is being returned. If you have some code after that point that already knows or figures out what type of person object you have, then you will simply have to cast it.
Below is a code example that illustrates what you could do on your factory and different usage scenarios, attempting to explain when you simply need to cast or when you don't.
public static class PersonFactory
{
public static Person CreatePerson()
{
return new Person();
}
public static Employee CreateEmployee()
{
return new Employee();
}
public static Pilot CreatePilot()
{
return new Pilot();
}
public static T CreatePerson<T>()
where T : Person
{
return (T)CreatePerson(typeof(T));
}
public static Person CreatePerson(Type type)
{
if (type == typeof(Person))
return CreatePerson();
else if (type == typeof(Employee))
return CreateEmployee();
else if (type == typeof(Pilot))
return CreatePilot();
else
throw new ArgumentOutOfRangeException(string.Format(CultureInfo.InvariantCulture, "Unrecognized type [{0}]", type.FullName), "type");
}
public static Person CreatePerson(string typeOfPerson)
{
switch (typeOfPerson)
{
case "Employee":
return CreateEmployee();
case "Pilot":
return CreatePilot();
default:
return CreateEmployee();
}
}
}
class UsageExample
{
Person GetPerson()
{
Pilot p;
p = (Pilot)PersonFactory.CreatePerson("Pilot"); // this code already knows to expect a Pilot, so why not just call CreatePilot or CreatePerson<Pilot>()?
p = PersonFactory.CreatePilot();
p = PersonFactory.CreatePerson<Pilot>();
return p;
}
Person GetPerson(Type personType)
{
Person p = PersonFactory.CreatePerson(personType);
// this code can't know what type of person was just created, because it depends on the parameter
return p;
}
void KnowledgableCaller()
{
Type personType = typeof(Pilot);
Person p = this.GetPerson(typeof(Pilot));
// this code knows that the Person object just returned should be of type Pilot
Pilot pilot = (Pilot)p;
// proceed with accessing Pilot-specific functionality
}
void IgnorantCaller()
{
Person p = this.GetPerson();
// this caller doesn't know what type of Person object was just returned
// but it can perform tests to figure it out
Pilot pilot = p as Pilot;
if (pilot != null)
{
// proceed with accessing Pilot-specific functionality
}
}
}
Do you have to use a string to communicate the type you want? You could use generics instead:
public static T CreatePerson<T>() where T : Person
Now it's hard to say exactly whether this will work or not, because we don't know the details of what you'd really be doing within CreatePerson. If it's just calling a parameterless constructor, that's easy:
public static T CreatePerson<T>() where T : Person, new()
{
return new T();
}
However, that's also reasonably pointless as the caller could do that instead. Is generics viable in your actual situation? If not, could you explain why not, and we could try to work around it?
There is no easy way around this.
In order to use the PilotNumber property you need the Pilot type. Using a Factory pattern means you are giving up the different sub-types of Person.
If it's any consolation, the BCL has similar patterns,
var req = WebRequest.CreateRequest("http://someUrl");
((HttpWebRequest)req).Contentlenght = ...;