提问人:arcadeperfect 提问时间:4/27/2022 最后编辑:slugsterarcadeperfect 更新时间:4/27/2022 访问量:249
在不中断引用的情况下覆盖引用类型
Overwrite reference type without breaking references
问:
我正在尝试编写一个系统,用于在运行时从磁盘加载一堆变量。对于 Unity 游戏。
我有一个包装类,允许将浮点数、整数等作为引用传递:
public class RefProperty<T>
{
private T val;
public T Val
{
get => val;
set => val = value;
}
public RefProperty()
{
}
public RefProperty(T value)
{
Val = value;
}
}
我想在不破坏引用的情况下用从磁盘加载的覆盖。在下文中,将更新 的值,但在修改时将不再更新。val
target = source
target
reference
target
public class Program
{
private RefProperty<float> source = new RefProperty<float>();
private RefProperty<float> target = new RefProperty<float>();
private RefProperty<float> reference = new RefProperty<float>();
public void Run()
{
target.Val = 1;
reference = target;
Debug.Log(reference.Val); // returns 1
source.Val = 5;
target = source;
Debug.Log(reference.Val); // returns 1
///////////////////////////////
target.Val = 1;
reference = target;
Debug.Log(reference.Val); // returns 1
source.Val = 5;
target.Val = source.Val;
Debug.Log(reference.Val); // returns 5
}
}
第二种方法确实有效。但是,我试图避免这种情况,因为最终我想遍历一个类的字段,其中包含具有不同类型的负载,以及一些子类,并替换所有值,而不必知道类型:target.Val = source.Val
public class RefPropertyChild : RefProperty<float>
{
// float specific features
public RefPropertyChild(float value)
{
Val = value;
}
}
public class Parameters
{
public RefProperty<bool> p1 = new RefProperty<bool>(true);
public RefProperty<int> p2 = new RefProperty<int>(5);
public RefPropertyChild p3 = new RefPropertyChild(6);
}
public class LoadData
{
private Parameters sourceParams;
private Parameters targetParams;
void load()
{
foreach (FieldInfo field in typeof(Parameters).GetFields())
{
field.SetValue(targetParams, field.GetValue(sourceParams));
}
}
}
和以前一样,这确实修改了值,但破坏了引用,我假设是因为它现在指向不同的内存位置?有什么方法可以做到这一点,或者我是否必须显式处理每种类型并使用 getter / setters?
答:
1赞
JonasH
4/27/2022
#1
一种解决方案是将引用替换为 ID,并将实际对象存储在其他地方。如果在序列化时使用某种 DTO 来表示对象,这可能更易于管理。像这样:
long maxId = 0;
var myReferences = new Dictionary<object, long>();
foreach(var obj in myObjects){
var r = obj.MyReferenceProperty;
var id = myReferences.TryGetValue(r, out var t) ? t: myReferences[r] = maxId++;
Use id in place of your property in the DTO or serialization format.
}
// Serialize the myReferences dictionary
反序列化时,您将执行相反的操作。反序列化引用列表,并将该属性替换为相应的引用对象。在执行字典序列化时,可能需要某种方法来包含类型信息,以便能够将属性反序列化为正确的类型。
某些序列化库内置了对此的支持。Protobuf .Net 具有 AsReference 属性,但看起来该属性已过时。
另一种选择是在运行时使用某种基于 id 的系统。因此,对象将共享一个公共的引用管理器对象。每当您需要读取或写入公共属性的值时,您都会将您的 ID 交给引用管理器并取回该值。这使得序列化更容易,但会使实现更加复杂。
评论