gpt4 book ai didi

c# - 拦截列表填充以在反序列化中分配值

转载 作者:行者123 更新时间:2023-11-30 17:34:17 25 4
gpt4 key购买 nike

我有一个递归类(树层次结构),它派生自一个列表,它有子项,它本身是通过 JSON.NET 中的反序列化填充的。

TLDR 版本是我想在该类存在的每个级别上从父级填充子级变量,而不使用来自 JSON.NET 的 $ref 变量(存储到 cookie 时节省空间) .

对于那些从昨天开始关注我的问题的人来说,这可能看起来像是重复的,但事实并非如此。这是相同的代码,但旧问题围绕着 JSON 中的 setter 没有被触发(已解决),而答案带来了这个问题(措辞更恰当)。

初始调用将是:

_Items = Cookies.Instance.GetJObject<CartItems>(COOKIE, jsonSetting);

调用:

public T GetJObject<T>(string cookieName, JsonSerializerSettings jset = null)
{
string cookieContent = Get(cookieName);
return JsonConvert.DeserializeObject<T>(cookieContent, jset);
}

自定义转换器类如下:

public class JsonCartConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(CartItem).IsAssignableFrom(objectType);
}

public override bool CanWrite
{
get
{
return false;
}
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
JObject obj = JObject.Load(reader);

var type = obj["t"] != null ? (CARTITEMTYPE)obj["t"].Value<int>() : CARTITEMTYPE.GENERIC;
var item = CartItems.NewByType(type);
serializer.Populate(obj.CreateReader(), item);
return item;
}


public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{

}
}

得到的JSON如下:

[{"t":1,"i":1,"n":4,"r":false,"c":[{"t":5,"i":2,"n":4,"r":false,"c":[]}]},{"t":1,"i":3,"n":4,"r":false,"c":[{"t":5,"i":4,"n":4,"r":false,"c":[{"t":4,"i":6,"n":14,"r":false,"c":[]}]},{"t":1,"i":5,"n":15,"r":false,"c":[]}]}]

我正在尝试做的事情与此类似:

public class CartItems : List<CartItem>{

public new CartItem Add(CartItem item)
{
item.Parent = this;
base.Add(item);
return item;
}

所以问题是我们已经确定反序列化不会从 List 调用标准的添加/插入方法来填充列表。我们知道它是通过反射创建列表,但如何创建呢?我能否在插入时拦截子类对父类的赋值,以便从父类中为子类分配一个变量(即 child.Parent = this)?

我尝试在 JSON.NET 源代码中四处寻找它用于填充的集合中的方法(因为即使使用反射,它也必须通过调用方法调用来添加它们,对吧?)。除非......它正在做这样的事情:

CartItems items = new CartItems() { new GenericItem() { }, new GenericItem() { } };

编辑:CartItems 是从列表派生的类。它填充了多个 CartItem 实例。

最佳答案

您的问题是您正在尝试子类化 List<T>在列表中添加和删除项目时保持父/子关系,但是 List<T>不设计为以这种方式进行子类化,因为相关方法都不是虚拟的。相反,您隐藏了 Add()方法通过 public new CartItem Add(CartItem item) ,但事实证明 Json.NET 并未调用此替换方法(并且没有理由假设它会调用)。

相反,您应该使用 Collection<T> 这是专门为此目的而设计的。来自docs :

The Collection<T> class provides protected methods that can be used to customize its behavior when adding and removing items, clearing the collection, or setting the value of an existing item.

因此您的对象模型应该如下所示:

public class CartItems : Collection<CartItem>
{
public CartItems() : base() { }

public CartItems(CartItem parent) : this()
{
this.Parent = parent;
}

public CartItem Parent { get; private set; }

protected override void RemoveItem(int index)
{
CartItem oldItem = null;
if (index >= 0 && index < Count)
{
oldItem = this[index];
}

base.RemoveItem(index);
}

protected override void InsertItem(int index, CartItem item)
{
base.InsertItem(index, item);
if (item != null)
item.Parent = this;
}

protected override void SetItem(int index, CartItem item)
{
CartItem oldItem = null;
if (index >= 0 && index < Count)
{
oldItem = this[index];
}

base.SetItem(index, item);

if (oldItem != null)
oldItem.Parent = null;

if (item != null)
item.Parent = this;
}

protected override void ClearItems()
{
foreach (var item in this)
if (item != null)
item.Parent = null;
base.ClearItems();
}
}

public class CartItem
{
public CartItem()
{
this.Children = new CartItems(this);
}

public int t { get; set; }
public int i { get; set; }
public int n { get; set; }
public bool r { get; set; }

[JsonProperty("c")]
public CartItems Children { get; private set; }

[JsonIgnore]
public CartItems Parent { get; set; }
}

请注意 CartItemCartItems有一个Parent属性(property)。 CartItems.Parent在其构造函数中分配。 CartItem.Parent由覆盖的 InsertItem 分配, SetItemRemoveItem方法。

样本 fiddle .

另见 Collection<T> versus List<T> what should you use on your interfaces? .

关于c# - 拦截列表填充以在反序列化中分配值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42723879/

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