在C#3.0上返回结构的引用而不是副本的引用?

时间:2018-04-19 09:46:08

标签: c# c#-3.0

我有这段代码:

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数组)上?

2 个答案:

答案 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变成一个班级?