Reputation: 1121
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?
Upvotes: 0
Views: 253
Reputation: 17382
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);
Upvotes: 1