gpt4 book ai didi

c# - 如何复制一个实际上是结构的对象(不是它的引用)?

转载 作者:可可西里 更新时间:2023-11-01 07:46:56 24 4
gpt4 key购买 nike

我有一个值(结构实例)被转换为 object 以进行通用处理。我需要复制该值。我不能明确地这样做,因为我只有它的 Type 并且不知道它在编译时是什么。

默认情况下,我会得到一个引用副本:var copy = objectOfMyStruct;。我考虑过通过 MemberwiseClone() 进行显式浅拷贝,但我不能这样做,因为它是 protected 方法,我不能修改 MyStruct

Convert.ChangeType(objectOfMyStruct, typeOfMyStruct) 没有帮助,因为转换(实际上没有转换)发生在内部并再次返回 Object。

我该怎么做?

编辑:

我需要制作一份副本以保留原始值并反序列化一个以传递给 OnChangeHandler。简化的实现是:

var oldValue = type.GetValue(reference);
var newValue = oldValue; // something better is needed here
Deserialize(type, stream, ref newValue);
OnChange(oldValue, newValue);
type.SetValue(reference, newValue);

复制是因为只发送增量(更改),所以应该应用于原始值。

编辑 2:

这个实现对于原始类型工作得很好,所以尽管 int 也被装箱了,但我正在复制它而不是复制对它的引用。我只是不明白这一点。


这是一个需要什么的例子。

这个例子,你可以在LINQPad中测试应该克隆结构而不将其转换回未装箱的类型,这样当它通过已实现接口(interface)的调用发生变化时,只有原始结构发生变化。因此,问题是;我该如何编写该 Clone 方法?

void Main()
{
object original = new Dummy { Property = 42, Field = "Meaning of life" };
object clone = Clone(original);

((IDummy)original).Mutate(); // will modify the boxed struct in-place
original.Dump();

// should output different if Clone did its job
clone.Dump();
}

static object Clone(object input)
{
return input;
}

public interface IDummy
{
void Mutate();
}

public struct Dummy : IDummy
{
public int Property { get; set; }
public string Field;

public void Mutate()
{
Property = 77;
Field = "Mutated";
}
}

最佳答案

我假设您不仅想要制作副本,而且还能够实际使用该副本。

为了使用它,您需要将它转换(拆箱)为适当的类型,这样可以有效地制作副本。事实上,即使将值放入框中也已经产生了一个副本。

因此,如果(例如)您知道这些对象是整数或 float ,您可以:

if (obj is int)
{
int i = (int) obj;
// do something with the copy in i
}
else if (obj is float)
{
float f = (float) obj;
// do something with the copy in f
}

如果要评估大量类型,可以使用 switch声明甚至 Dictionary<Type,Action<object>> .

如果你需要处理你在编译时不知道的类型(某些类型通过某种插件机制动态添加)那么这是不可能的,但话又说回来,这也是不可能的对对象做任何事情(除非通过接口(interface))。

更新:

既然你改变了你的问题,这里有一个更好的答案:你不需要制作副本,它是通过装箱结构为你制作的。

例子:

int i = 42;

// make a copy on the heap
object obj = i;

// modify the original
i = i + 1;

// copy is not modified
Debug.Assert((int)obj == 42);

显然,我使用的是 int这里是为了方便,但它适用于每个结构。如果该结构实现了一个接口(interface),您可以将该对象转换为该接口(interface)(不会制作第二个副本)并使用它。它不会修改原始值,因为它是在框内的副本上操作。

更新 2:

非常明确:这适用于每个结构。例如:

interface IIncrementor
{
void Increment();
}

struct MyStruct : IIncrementor
{
public int i;

public void Increment()
{
this.i = this.i + 1;
}

public override string ToString()
{
return i.ToString();
}
}

// in some method:

MyStruct ms = new MyStruct();
ms.i = 42;

Console.Writeline(ms); // 42

object obj = ms;

IIncrementable ii = (IIncrementable) obj;
ii.Increment();

Console.Writeline(ms); // still 42

Console.Writeline(ii); // 43

还有一个更新:

代替

object original = new Dummy { Property = 42, Field = "Meaning of life" };
object clone = Clone(original);

Dummy original = new Dummy { Property = 42, Field = "Meaning of life" };
object clone = original;

你会没事的。

关于c# - 如何复制一个实际上是结构的对象(不是它的引用)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19591281/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com