My purpose is getting the data from user interface and saving it as a configuration. The program allows to config multiple person so i am trying to save each person settings. I have realized something. Whenever i change the data from one instance, the other instances values change.
public class Person()
{
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
public void Change()
{
Name = "F";
}
}
This is my person class
This is my main
static void Main(string[] args)
{
Person person = new Person();
Person person2 = new Person();
Person current = new Person();
person.Name = "John";
person2.Name = "Doe";
current.Name = "Robert";
person = current;
person2 = current;
current.Change()
}
after current.Change() the person 1 and person 2 name changes to "F". This behavious got me confused because i would expect this result on
person = current;
person2 = current;
current.Change()
person = current;
person2 = current;
What i want is to use current on the interface. Get the datas and save them to person instances. The problem is, when i change current, all other instance properties change to same and i lose my config settings.
How can i achieve my purpose? Any ideas?
Thank you so much! Sorry for bad English.
Since Person is a reference type, when you do person2 = current; you are in fact just pointing the person2 reference to the current object in memory, which is also pointed to by person.
Thus, any changes made via one reference will change the same physical object in memory as any changes made via the other reference.
What you need to do is to make an actual copy of the object.
One common way to do this is to write a "Copy constructor" to make a copy. You can also write a Copy() method that uses the copy constructor for implementation, but that isn't really necessary unless you have an inheritance hierarchy.
Here's how your Person class would look with a copy constructor and (for completeness) a Copy() method:
public class Person
{
private string _name;
public Person() // Default constructor is required if there are any other constructors!
{
Name = "";
}
public Person(Person other) // Copy constructor.
{
this.Name = other.Name;
}
public Person Copy()
{
return new Person(this); // Use copy constructor to return a copy of this.
}
public string Name
{
get { return _name; }
set { _name = value; }
}
public void Change()
{
Name = "F";
}
}
You would then use this as follows, for your sample:
static void Main()
{
Person person = new Person();
Person person2 = new Person();
Person current = new Person();
person.Name = "John";
person2.Name = "Doe";
current.Name = "Robert";
person = new Person(current); // Using Copy Constructor.
person2 = current.Copy(); // Using Copy() method.
current.Change(); // Only changes current, not person or person2.
}
Note: I recommend that you don't implement the Copy() method and just stick to the copy-constructor unless (as noted previously) there is an inheritance hierarchy for your class. That would be advanced usage beyond the scope of this answer!
Related
So I've been trying to play around little bit with a NuGet package called DeepCloner.
I have a simple class called IdInfo with one property and constructor
public class IdInfo
{
public int IdNumber;
public IdInfo(int idNumber)
{
IdNumber = idNumber;
}
}
Then, I have a class called Person, with couple of properties and constructors
public class Person
{
public int Age;
public DateTime BirthDate;
public string Name;
public IdInfo IdInfo;
public Person(int age, DateTime birthDate, string name, IdInfo idInfo)
{
Age = age;
BirthDate = birthDate;
Name = name;
IdInfo = idInfo;
}
public Person()
{ }
}
In my main class, I would like to achieve Deep cloning by using DeepCloner as mentioned above. This is what I have tried
internal class Program
{
static void Main(string[] args)
{
//create a dummy Person to get cloned
Person p1 = new Person();
p1.Age = 42;
p1.BirthDate = Convert.ToDateTime("1977-01-05");
p1.Name = "Aleksandar Petrovic";
p1.IdInfo = new IdInfo(123);
//create a dummy Person to append those values to
Person clonedPerson = new Person();
//call a method for DeepCloning (down in the code)
PerformDeepCloning(p1, clonedPerson);
//after finishing with the method, "clonedPerson" value stay null, why?
Console.WriteLine("Displaying values of both persons (1. p1, 2. Cloned person)\n");
DisplayValues(p1);
//System.NullReferenceException: 'Object reference not set to an instance of an object.'
DisplayValues(clonedPerson);
}
public static void DisplayValues(Person p)
{
Console.WriteLine(" Name: {0:s}, Age: {1:d}, BirthDate: {2:MM/dd/yy}", p.Name, p.Age, p.BirthDate);
Console.WriteLine(" ID#: {0:d}\n", p.IdInfo.IdNumber);
}
//method gets 2 elements, first has values that should be copied to the second
public static void PerformDeepCloning(Person source, Person destination)
{
//call a method from the package
destination = source.DeepClone();
//this works fine
Console.WriteLine("DEEP CLONED NAME = " + destination.Name);
}
}
I understand why the values are shown in the SC down below
But why are the values not applied to the variable "clonedPerson" afterwards?
As your code is currently written, you are assigning a complete new object to your destination parameter. But this does not change the object you passed into that parameter. To overcome this issue there are several possibilites (in order of my personal preference)
You can just define PerformDeepCloning to return a Person
public static Person PerformDeepCloning(Person source)
{
//call a method from the package
Person destination = source.DeepClone();
//this works fine
Console.WriteLine("DEEP CLONED NAME = " + destination.Name);
return destination;
}
and call it like this
Person otherPerson = PerformDeepCloning(person);
This would seem the most natural way for me to do it, instead of populating out or ref parameters of a method returning void, why not just return the result via return keyword?
Use the out keyword which was specifically designed for such situations (ie creating a new object inside the called method and pass it to the caller if return isn't possible for whatever resons)
public static void PerformDeepCloning(Person source, out Person destination)
{
//call a method from the package
destination = source.DeepClone();
//this works fine
Console.WriteLine("DEEP CLONED NAME = " + destination.Name);
}
and then call it like this
//you must not assign a value here, when using the out keyword
Person otherPerson;
PerformDeepCloning(person, out otherPerson);
or starting with C#7 you can also use an inline declaration
//no need to delare Person otherPerson; prior to the call
PerformDeepCloning(person, out Person otherPerson);
Use the ref keyword which is capable of updating the reference which was passed in.
public static void PerformDeepCloning(Person source, ref Person destination)
{
//call a method from the package
destination = source.DeepClone();
//this works fine
Console.WriteLine("DEEP CLONED NAME = " + destination.Name);
}
and then call it like this
Person otherPerson = new Person();
PerformDeepCloning(person, ref otherPerson);
But as you are creating a new instance of a Person anyways, you don't need to create a new object before the call (because this will be thrown away immediately) but initialize the otherPerson with null. But then you of course have to sure, you don't access otherPerson's properties, before you created an instance.
Person otherPerson = null;
PerformDeepCloning(person, ref otherPerson);
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();.
I am new to C#, and writing a piece of code to do some exercises. What surprises me is that I can use undefined member variables in a C# class as if they had been defined. Below is my code. In class Person, I only defined "myName" and "myAge," but I can use the member variables "Name" and "Age" without any issue. The code can be compiled and the executable can be run. Can someone tell me why I can use "Name" and "Age" without defining them? Many thanks,
C# code
======================================
using System;
namespace prj01
{
class Person
{
private string myName = "N/A";
private int myAge = 0;
public string Name
{
get
{
return myName;
}
set
{
myName = value;
}
}
public int Age
{
get
{
return myAge;
}
set
{
myAge = value;
}
}
public override string ToString()
{
return "Name = " + Name + ", Age = " + Age;
}
}
class Program
{
static void Main(string[] args)
{
// property
Console.WriteLine("Simple Properties");
Person person01 = new Person();
Console.WriteLine("Person details - {0}", person01);
person01.Name = "Joe"; // Why can I use "Name"?
person01.Age = 99; // Why is "Age" accessible and usable?
Console.WriteLine("Person details - {0}", person01);
Console.ReadLine();
}
}
}
======================================
You did define them. Right here:
public string Name
{
get
{
return myName;
}
set
{
myName = value;
}
}
public int Age
{
get
{
return myAge;
}
set
{
myAge = value;
}
}
These are called "properties" in .NET classes. In your current code, they're essentially "pass-through" properties which do nothing but delegate access to the member variables. They compile into getter and setter methods wrapping those member variables.
Name and Age are public properties, these are used by code external to the class to send in data, that is, to modify the private variables. If you change the public beside Name to private, you won't be able to use that property because of the protection level: What is the difference between Public, Private, Protected, and Nothing?
.Net classes expose 2 types of data members
1>Fields :
in your example they are myName and myAge, since they are private you can only use them within your class members.
2> Properties
In you class they are Name and Age.
Since they are public they can be accessed within and outside your class.
With properties you can getters and/or setters.
getters enable you to read Value from a property eg :
Person person01 = new Person();
int xyz = person01.Age; // it is internally calling person01.Age.get();
and setters enable setting value for the property ie
Person person01 = new Person();
person01.Age = 2;// this is internally calling person01.Age.set(2);
Hope this clarifies.
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.
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
for example, I'm trying to initialize a new Person
var me = new Person();
but i'm just wondering if it's possible for that initialization to automatically return a seed?
I'm trying to add it to the constructor but I don't know how?
public class Person
{
public Person Person(){ return ...}
}
well, that doesn't really work. Can anyone explain to me why it doesn't work and if there's another way to do this?
I can do object initialization, but I'm just wondering if this is possible??
you can create a static method (factory)
var seededPerson = Person.CreateNew();
public class Person
{
private Person() {}
public static Person CreateNew()
{
return new Person() { Seed = 123; };
}
}
A constructor initializes the current (newly allocated) instance; nothing more. It cannot return anything. It sounds like you just want a factory method:
public class Person
{
public static Person Create(){ return ...}
}
From your comment:
automatically adds value to the variable (in this case "me") and populating the instantiated object.. ie: having Person.Name = "Joe" and etc... without me manually doing object initialization or what not... basically I want the model/class to create its own data right after I instantiate it..
Just add implementation to the parameterless constructor:
public class Person
{
public Person()
{
this.Name = "Joe";
}
public string Name { get; set; }
}
When you call var me = new Person();, then Name will already be populated with "Joe".
More usages of constructors
If you want to be able to customize the name more quickly, then you could add parameters to that constructor, or add a different constructor that takes parameters:
public class Person
{
public Person()
: this("Joe") // Calls the other constructor that takes a name...
{
}
public Person(string name)
{
this.Name = name;
}
public string Name { get; set; }
}
var me = new Person(); // Joe
var you = new Person("You");
In the latest .Net, you can also use default values for these parameters to make your code shorter:
public class Person
{
public Person(string name = "Joe") // Will be "Joe" unless you say otherwise
{
this.Name = name;
}
public string Name { get; set; }
}
var me = new Person(); // Joe
var you = new Person("You");
public class Person
{
protected Person()
{
}
public static Person BuildPerson(out int seed)
{
var person = new Person();
seed = RuntimeHelpers.GetHashCode(person);
return person;
}
}
You mean this? Using a "surrogate" constructor based on a static method?
or
public class Person
{
public Person(out int seed)
{
seed = RuntimeHelpers.GetHashCode(this);
}
}
a constructor with an out argument?
As a sidenote, RuntimeHelpers.GetHashCode(object) returns a pseudo unique id of an object. Pseudo unique because these numbers can be reused by .NET. A better "implementation" that always give unique ids would be:
public class Person
{
private static int seed;
public Person(out int seed)
{
seed = Interlocked.Increment(ref Person.seed);
}
}
using the Interlocked.Increment to make the constructor thread safe.