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);
Related
I was trying to understand properties better and I came across this page with this example:
https://www.tutorialspoint.com/csharp/csharp_properties.htm
using System;
namespace tutorialspoint {
class Student {
private string code = "N.A";
private string name = "not known";
private int age = 0;
// Declare a Code property of type string:
public string Code {
get {
return code;
}
set {
code = value;
}
}
// Declare a Name property of type string:
public string Name {
get {
return name;
}
set {
name = value;
}
}
// Declare a Age property of type int:
public int Age {
get {
return age;
}
set {
age = value;
}
}
public override string ToString() {
return "Code = " + Code +", Name = " + Name + ", Age = " + Age;
}
}
class ExampleDemo {
public static void Main() {
// Create a new Student object:
Student s = new Student();
// Setting code, name and the age of the student
s.Code = "001";
s.Name = "Zara";
s.Age = 9;
Console.WriteLine("Student Info: {0}", s);
//let us increase age
s.Age += 1;
Console.WriteLine("Student Info: {0}", s);
Console.ReadKey();
}
}
}
output: Student Info: Code = 001, Name = Zara, Age = 9
I don't understand how the first example is able to output the whole line written in the class "student". In the main method, we are using "s" which is an object created in the class "exampledemo". How is it able to call a method from another class?
I guess it's something related to inheritance and polymorphism (I googled the override keyword) but it seems to me that the two classes are indipendent and not a subclass of the other.
I'm a total beginner at programming and probably quite confused.
s is of type Student (as declared on the first line of Main()). Therefore one can call a method on the object to modify it or print it. When you do s.Name = "Zara"; you are already calling a method on Student to update it (technically, a method and a property are the same, they only differ by syntax).
The line Console.WriteLine("Student Info: {0}", s); is actually the same as Console.WriteLine("Student Info: " + s.ToString());. The compiler allows writing this in a shorter form, but internally the same thing happens.
Let me show a real life example.
You have a sketch of your dream bicycle. Your bicycle exists only in sketch. This is a class.
Then you are going to garage and building your bicycle from the sketch. This process can be called like creation of object
of bicycle at factory from your sketch.
According to your example, class is Student.
You are creating an object by the following line:
Student s = new Student();
Object takes space in memory. How can we read values of objects from memory? By using object reference.
s is an object reference to the newly created object type of Student.
How is it able to call a method from another class?
s is an object reference to the newly created object type of Student. So it can call any public method of this object.
I was trying to understand properties
Properties are evolution of getter and setter methods. Looking for a short & simple example of getters/setters in C#
The compiler generates a pair of get and set methods for a property, plus a private backing field for an auto-implemented property.
Are C# properties actually Methods?
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!
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();.
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.