繁体   English   中英

如何让一个类对象在c#中存储另一个类对象?

[英]How to get a class object to store another class object in c#?

假设我们在下面有C#代码,它在类B中存储了一个A类实例。我想创建一个B类版本来存储它自己的A.所以当我们在A外部改变A时,B中的内部A对象不会改变。

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
    }
}

我可以通过使用模板化的桥类来避免C ++中的这个问题,该类在将A传递给B时克隆A.但是由于某些原因,显然深度克隆似乎没有在C#中广泛使用(为什么?)。 谁能提供一个解决这个存储问题的好方法。

C ++代码:

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;
}

如果您克隆的对象包含值类型,则使用Clone()只会满足您的需求,但通常(如您的示例中)您将拥有具有其他引用类型属性的类,而浅层副本(通过Clone())将只复制一个参考。

你想要的是一个深层副本,可以通过在所有属性为ref类型或通过序列化实现复制构造函数来完成。

序列化是执行深层复制的最简单方法: 深度克隆对象

复制构造函数做深复制示例:

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;
    }
}

请记住,您正在传递参考文献。 如果您将实例化的A副本传递给某个东西,那么您将A的副本传递给它(就好像您已经通过了&a,在C中)。

由于类都是引用类型,因此在C#中,必须在某处明确地进行复制。 这是一个使用匿名构造函数来复制您关注的值的解决方案。

    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
    }

请记住,这是一个简单的解决方案,但如果您需要复制您正在复制的类可能包含的任何引用类,则会变得很麻烦。 在这种情况下,由@TMcKeown发布的ICloneable解决方案更安全,并且总是更强大(假设您维护它!)。

通过使用像这样的复制构造函数来解决问题的另一种方法

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;
}

希望它会对你有所帮助

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM