简体   繁体   English

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

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

Suppose we have the C# code below 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 of B, the internal A object in B doesn't change. 假设我们在下面有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
    }
}

I can avoid this problem in C++ by using a templated bridge class that clones A when passing A into B. But apparently deep clones doesn't seem as widely used in C# for some reason(why?). 我可以通过使用模板化的桥类来避免C ++中的这个问题,该类在将A传递给B时克隆A.但是由于某些原因,显然深度克隆似乎没有在C#中广泛使用(为什么?)。 Can anyone provide a good way around this storing problem. 谁能提供一个解决这个存储问题的好方法。

C++ code: 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;
}

Using Clone() will only satisfy your needs if the object you are cloning contains value types, but typically (as in your example) you would have a class with other reference types properties and a shallow copy ( via Clone() ) will simply copy a reference. 如果您克隆的对象包含值类型,则使用Clone()只会满足您的需求,但通常(如您的示例中)您将拥有具有其他引用类型属性的类,而浅层副本(通过Clone())将只复制一个参考。

What you want is a deep copy and that can be done either by implementing copy constructors on all your properties that are ref types or thru Serialization. 你想要的是一个深层副本,可以通过在所有属性为ref类型或通过序列化实现复制构造函数来完成。

Serialization would be the simplest way to perform a deep copy: Deep cloning objects 序列化是执行深层复制的最简单方法: 深度克隆对象

Copy constructors doing 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;
    }
}

Remember that you're passing references around. 请记住,您正在传递参考文献。 If you pass your instantiated copy of A into something, you're passing THAT copy of A into it (as if you had passed &a, in C). 如果您将实例化的A副本传递给某个东西,那么您将A的副本传递给它(就好像您已经通过了&a,在C中)。

Since classes are all reference types, in C#, copying must be done explicitly, somewhere. 由于类都是引用类型,因此在C#中,必须在某处明确地进行复制。 Here's a solution using an anonymous constructor to copy the value you care about. 这是一个使用匿名构造函数来复制您关注的值的解决方案。

    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
    }

Bear in mind this is an easy solution, but it gets cumbersome if you need to make deep copies of any reference classes that the class you're copying might also contain. 请记住,这是一个简单的解决方案,但如果您需要复制您正在复制的类可能包含的任何引用类,则会变得很麻烦。 In that case, the ICloneable solution posted by @TMcKeown is safer and is always more robust (assuming you maintain it!). 在这种情况下,由@TMcKeown发布的ICloneable解决方案更安全,并且总是更强大(假设您维护它!)。

another way to solve your problem, by using the 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 it will help you 希望它会对你有所帮助

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

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