我有这段代码:
using System;
using System.Collections.Generic;
using UnityEngine;
public interface HaveId
{
int id { get; }
}
public struct BusinessData : HaveId
{
// business type data
public int graphic_asset_id;
public string name;
public int id { get; set; }
}
public class LookupHelper<T> where T: HaveId
{
private T[] _list;
public T[] list
{
get { return _list; }
set { _list = value; _mapToDictionary(); }
}
private Dictionary<int, int> idxById = new Dictionary<int, int>();
public LookupHelper(){}
private void _mapToDictionary()
{
if(idxById.Count > 0) idxById = new Dictionary<int, int>();
for(var z =0 ; z < list.Length; ++z)
{
idxById[list[z].id] = z;
}
}
public bool IsIdExists(int id)
{
return idxById.ContainsKey(id);
}
public T ById(int id) // is this a reference?
{
var idx = idxById[id];
if (idx >= list.Length) throw new Exception(
String.Format("Invalid Index: {0} >= {1} on {2}",idx.ToString(),list.Length.ToString(), typeof(T).Name)
);
return list[idx];
}
}
测试代码:
LookupHelper<BusinessData> bd = new LookupHelper<BusinessData>();
bd.list = new BusinessData[]
{
new BusinessData{id = 1, name = "test"},
new BusinessData{id = 2, name = "test2"},
};
bd.ById(1).name = "foo";
这会出错:"Cannot modify struct member when accessed struct is not classified as a variable"
如何更改第一个BusinessData
的值并保持数组仍然分配在连续内存(缓存局部所需的struct数组)上?
答案 0 :(得分:0)
这应该是将其分成几行的简单问题。提取对象以获取副本,修改副本,然后在数组中覆盖它:
BusinessData bsd = bd.ById(1);
bsd.name = "foo";
bd.SetById(1, bsd);
当然,您需要编写SetById
方法来重新插入数组:
public void SetById(int id, T obj)
{
Int32 idx = idxById[id];
list[idx] = obj;
}
答案 1 :(得分:0)
如你所知C#从C和Java中借用了一些东西。但不是一切。
在C中,您可以在堆栈或堆上为struct
创建一个位置。在堆上,我可以传递指针并更改内容。非常强大。
但是C#强调通过垃圾收集来简化内存管理。为了简单起见,C#具有将值类型装入System.Object的概念。其他详细信息可在Microsoft C# Programming Guide on Boxing and unboxing上找到。
因此,当您访问列表中的值类型时,必须显式取消设置值。因此,它是列表中项目的副本。你可以做@Nyerguds的建议。
但为了让生活变得轻松,为什么不把你的BusinessData
变成一个班级?