将一个类复制到另一个类?

9

I have

class A
{
    public int a;
    public string b;
}

如何将A复制到另一个A?在C++中,我知道可以使用*a1 = *a2;。在C#中是否有类似的方法?我知道可以使用反射编写通用解决方案,但我希望已经存在某些方法。

我正在考虑将A更改为可空结构体。

第二步我需要执行:

class B : A {}
class C : A {}

将基础数据从B复制到C。

你已经在这里提问过了:http://stackoverflow.com/questions/2067725/best-way-to-convert-a-shared-base - user47589
@yodaj007: 他从那个问题中理清了自己的想法。我已经投票关闭了旧的那个问题。 - Austin Salonen
我已经有一段时间没写C++代码了。你的示例仅确保a1a2指向内存中的同一对象,因此对其中一个所做的更改会反映在两者中,对吗?因此,这并不真正是将其复制到另一个A中,对吗? - Austin Salonen
不对。*obj = 与 obj= 是不同的。obj= 改变指针,而 *obj 复制内容。 - user34537
我最近也遇到了类似的问题,并想出了一种通用方法 - 它确实使用了反射:http://pmichaels.net/2016/03/04/dynamically-copy-a-class-from-one-instance-to-another-using-reflection/ - Paul Michaels
8个回答

8

我已经使用了二进制序列化。基本上,将实例序列化到内存流中。然后,从内存流中反序列化出来。你将拥有一个完全相同的二进制副本。这将是深度复制,而不是浅层复制。

class a = new ClassA();

class b = MySerializationMethod(a);

对于浅复制,您可以使用 Object.MemberwiseClone


这种方法很棒,我们已经使用多次并且得到了很好的效果。+1。 - womp
看起来 Object.MemberwiseClone 只能在两个类相同且在类方法内部使用?我该如何编写 MySerializationMethod?似乎需要使用反射。 - user34537
不需要反射。 - Jeremy Samuel

8

这里有一些简单的代码,适用于任何类,而不仅仅是基类。

    public static void DuckCopyShallow(this Object dst, object src)
    {
        var srcT = src.GetType();
        var dstT= dst.GetType();
        foreach(var f in srcT.GetFields())
        {
            var dstF = dstT.GetField(f.Name);
            if (dstF == null || dstF.IsLiteral)
                continue;
            dstF.SetValue(dst, f.GetValue(src));
        }

        foreach (var f in srcT.GetProperties())
        {
            var dstF = dstT.GetProperty(f.Name);
            if (dstF == null)
                continue;
            
            dstF.SetValue(dst, f.GetValue(src, null), null);
        }
    }

5
假设 A 是一个简单的类,你可以这样做:
A newA = instanceOfA.MemberwiseClone();

MemberwiseClone()方法是一种浅复制,如果你的类变得复杂,其中的属性也是引用类型,那么这种方法就不适用了。


1
虽然这可能不如非反射方法快。 - Hamish Grubijan
同意。相比自定义方法,它可以更方便和可扩展。 - womp

4

4

3
添加适当的构造函数:
class Foo
{
    public Foo(int a, string b)
    {
        A = a;
        B = b;
    }

    public Foo(Foo other)
    {
        A = other.A;
        B = other.B;
    }

    public int A { get; set; }
    public string B { get; set; }
}

如果您考虑将其转换为结构体,则还应考虑使其不可变。可变的结构体是有害的。

最后,当您从一个类继承时,您不需要将基类的成员复制到子类中。


如果我今天有足够的投票,就加1。不可变意味着没有设置属性,对吗? - Hamish Grubijan
@lpthnc:使用private set即可。 - Bruno Reis
谢谢。如果你想将get声明为public,你会如何声明 - 在同一行还是分开声明? - Hamish Grubijan
1
@Ipthnc:public int A { get; private set; } - Mark Byers

2
我们已经成功地使用了这段代码:
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;

namespace Utility {
    internal static class ObjectCloner {
        public static T Clone<T>(T obj) {
            using (MemoryStream buffer = new MemoryStream()) {
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(buffer, obj);
                buffer.Position = 0;
                T temp = (T)formatter.Deserialize(buffer);
                return temp;
            }
        }
    }
}

也许还有其他更好的方法,但也许这个可以帮到你。
克里斯

0

你可以使用Clone方法,也可以定义一个拷贝构造函数。为什么要因为在C++中只需要10个字符就改变类为结构体呢?C#是不同的。结构体有其优缺点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接