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";
Related
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();.
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.
I have an object
public class School
{
public Employee Emp{get;set;}
public string City{get;set;}
}
public class Employee
{
public string Name{get;set;}
}
Using reflection I need to fetch this Employee Name from the school object
I Tried
School schl=New School();schl.Employee=new Employee{Name="Shalem"};
var empName= schl.GetType().GetProperty("Emp.Name").GetValue(schl, null)
Also tried
PropertyDescriptorCollection allProp= TypeDescriptor.GetProperties(schl);
var empName=allProp["Emp.Name"].GetValue(schl);
I always get null. How can i get?
Note: The thing is i dont know what object it will contain. But all i know is i will get the exact name with inner object like "Emp.Name" etc. Need a generic solution
School schl=New School();
schl.Employee=new Employee{Name="Shalem"};
var emp = schl.GetType().GetProperty("Emp").GetValue(schl, null)
var empName = emp.GetType().GetProperty("Name").GetValue(emp, null);
Split it up, get the Employee object and then get the Name of the Employee.
Although I don't see the benefit for this in this instance when you can do string empName = schl.Employee.Name - unless the scope of the code is different?
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.