How do I get a class object to store another class object in C #?
Suppose we have below C # code that stores an instance of class A in class B. I want to create a version of class B that stores its own A. So when we change A outside B, the inner object of A in B does not change ...
class Engine
{
public int Horesepower = 500;
}
class Vehicle
{
public Vehicle( Engine engine ) { Engine = engine; }
public Engine Engine;
}
class Program
{
static void Main( string[ ] args )
{
Engine v8 = new Engine( );
Vehicle monsterTruck = new Vehicle( v8 );
v8.Horesepower = 1000; // this changes the field Engine in yugo as well
Console.WriteLine( monsterTruck.Engine.Horesepower ); // prints 1000 instead of 500
}
}
I can avoid this problem in C ++ by using a templated bridge class that clones A when passing A to B. But apparently deep clones are not widely used in C # for some reason (why?). Can anyone provide a good way to solve this storage problem.
C ++ code:
template <typename T>
class Wrapper{
public:
Wrapper(const Wrapper<T> &orig){if(orig.data!=nullptr)data = orig.data->clone();}
Wrapper(const T &origdata){data = origdata.clone();}
Wrapper & operator=(const Wrapper<T> &orig){...}
...
~T(){delete data;}
private:
T *data;
}
class A{
public:
A():data(9){}
int data;
A *clone(){return new A(*this);}
}
class B{
public:
B(const Wrapper<A>& a_):ainner(a_){}
Wrapper<A> ainner;
}
int main(){
A a;
B b(a);
a.data =20;
std::cout << b.ainner.data; // prints 9 still
return 0;
}
source to share
The usage Clone()
will only satisfy your needs if the cloned object contains value types, but usually (as in your example) you will have a class with different reference type properties and a shallow copy (via Clone ()) just copy the reference.
What you want is a deep copy and this can be done either by creating copy constructors in all of your properties, which are reference types, or through serialization.
Serialization would be the easiest way to do a deep copy: Deep cloning objects
Copy constructors making deep copy example:
class Engine
{
public Engine( ) { }
public Engine( Engine e ) { Horesepower = e.Horesepower; }
public int Horesepower = 500;
}
class Vehicle : ICloneable
{
public Vehicle( Engine engine ) { Engine = engine; }
public Vehicle( Vehicle v ) { Engine = new Engine( v.Engine ); }
public Engine Engine;
public object Clone( )
{
Vehicle newVehicle = new Vehicle( this );
return newVehicle;
}
}
source to share
Remember that you are passing links. If you pass an instance of A to some instance, you pass that copy of A into it (as if you passed & a, in C).
Since classes are reference types, in C # copying has to be done explicitly, somewhere. Here is a solution using an anonymous constructor to copy the value you need.
static void Main( string[ ] args )
{
Engine v8 = new Engine( );
v8.Horesepower = 1000; // this changes the field Engine in yugo as well
Vehicle monsterTruck = new Vehicle( new Engine { Horesepower = v8.Horesepower } );
Console.WriteLine( v8.Horesepower ); // prints 1000
Console.WriteLine( monsterTruck.Engine.Horesepower ); // prints 1000
v8.Horesepower = 800;
monsterTruck.Engine.Horesepower = 1200;
Console.WriteLine( v8.Horesepower ); // prints 800
Console.WriteLine( monsterTruck.Engine.Horesepower ); // prints 1200
}
Remember, this is a simple solution, but cumbersome if you need to make deep copies of any referenced classes that may also contain the class you are copying. In this case, the ICloneable solution posted by @TMcKeown is safer and always more reliable (if you support it!).
source to share
another way to solve your problem using copy constructors like this
using System;
public class Program
{
public static void Main()
{
A foo = new A();
B bar = new B(foo);
foo.data = 20;
Console.WriteLine(bar.a.data); // prints 9
}
}
class A
{
public int data = 9;
public A()
{
}
public A(A a)
{
this.data=a.data;
}
}
class B
{
public B(A a_) { a = new A(a_); }
public A a;
}
hope this helps you
source to share