我已经阅读了很多关于c#中结构的可变性的内容。大多数词都说可变结构是邪恶的。我知道为什么。 但我有一个案例,其中可变结构似乎是合法的。当然,我面临着围绕结构可变性的问题。
说,我在GIS编辑器应用程序中有一个这样的简单结构:
enum CoordinateSystem : byte { .... } // coordinate system types
struct Vertex
{
float m_x; // m_ is the original value of coordinate, it needs to be kept
float m_y;
float c_x; // c_ is a cache of the result of expensive coordinate transformation
float c_y;
CoordinateSystem cachedSystem; // the current coordinate system type in c_x and c_y
public float x { get {...} set {...}} // properties are for accessing values outside of struct
public float y { get {...} set {...}} // and transforming m_x,m_y into c_x,c_y if necessary
}
属性用于从外部访问坐标。从外部单例类中可以知道结构在访问x和y属性时需要什么样的坐标系。如果需要,get属性将按需转换m_x和m_y,并返回值,它将结果存储在c_x和c_y中以进行更多访问。当然,缓存是必要的,因为坐标转换非常昂贵。使用缓存时,只有第一次访问会很慢,并且在同一坐标系中的所有进一步访问都是“立即”。
顶点位于List中,所以基本上长度为10000的顶点列表被分配为列表中的顶点[10000]。
显然,问题是从列表中访问(离开)Vertex会返回存储在List<>中的结构的副本。因此,转换后的缓存没有任何效果,因为它将结果存储在短生活副本中,而不是存储在List<>中。本身。
我不想将Vertex更改为类,因为它会在一个块中分配(在64位运行时)10000 * 8字节作为引用,在10000块中分配10000 * 17字节,这大约是+ 1/3内存和分配块数量的10000倍。 (我知道这是一个粗略的计算,因为对齐,...) 这是关于一个顶点列表,我有成千上万的顶级列表,因此类会浪费大量内存。
我想保持转换对外部访问器透明,因为Vertex是多次引用的应用程序中的核心类型。另一个原因是只有顶点知道坐标系,所有其他部分都将Vertex.x和Vertex.y视为“数字”,仅此而已。这样x和y属性就可以进行转换。
问题是:解决这个问题的正确方法是什么?
(请不要将此问题视为基于意见的。这不是其中之一。考虑到申请的目的,我对基于事实的答案感兴趣。)
答案 0 :(得分:0)
Ivan Stoyev告诉我们"数组,它们是目前唯一允许通过索引器变换结构元素的集合结构"。 并列出<>使用数组。
所以我选择了一个肮脏的,应受谴责的,非原谅的和邪恶的解决方案,我预见到了downvotes ......但是我必须有一个适合内存中数十亿字节数据的解决方案而不需要更改太多代码。
我修改了List<>的索引器。 class to mutate(重新计算)访问列表元素时存在于存储数组中的struct的缓存部分。
不幸的是,List<>的存储数组是私有的,不受保护,无法通过继承访问它。所以我进一步采用更恶魔的方式:从referencesource我复制了List<>的源代码的必要部分。 (当然,我的名字不同)最后我有了一个新的List<>功能,但能够在访问索引器时更新内容。
同样,这是一个永远不应该被任何人遵循的解决方案。 但它运作良好......