I\'m writing a game that has a huge 2D array of \"cells\". A cell takes only 3 bytes. I also have a class called CellMap, which contains the 2D array as a private field, and pro
Eric Lippert's approach is good, but I would suggest using a base class rather than an interface for the indirect accessor. The following program demonstrates a class which acts like a sparse array of points. Provided that one never persists any item of type PointRef(*), things should work beautifully. Saying:
MyPointHolder(123) = somePoint
or
MyPointHolder(123).thePoint = somePoint
will both create a temporary pointRef object (a pointRef.onePoint in one case; a pointHolder.IndexedPointRef in the other) but the widening typecasts work to maintain value semantics. Of course, things would have been much easier if (1) methods on value types could be marked as mutators, and (2) writing a field of a structure accessed via property would could automatically read the property, edit the temporary structure, and write it back. The approach used here works, though alas I don't know any way to make it generic.
(*) Items of type PointRef should only be returned by properties, and should never be stored in a variable or used as parameters to anything other than a setter property which will convert to a Point.
MustInherit Class PointRef
Public MustOverride Property thePoint() As Point
Public Property X() As Integer
Get
Return thePoint.X
End Get
Set(ByVal value As Integer)
Dim mypoint As Point = thePoint
mypoint.X = value
thePoint = mypoint
End Set
End Property
Public Property Y() As Integer
Get
Return thePoint.X
End Get
Set(ByVal value As Integer)
Dim mypoint As Point = thePoint
mypoint.Y = value
thePoint = mypoint
End Set
End Property
Public Shared Widening Operator CType(ByVal val As Point) As PointRef
Return New onePoint(val)
End Operator
Public Shared Widening Operator CType(ByVal val As PointRef) As Point
Return val.thePoint
End Operator
Private Class onePoint
Inherits PointRef
Dim myPoint As Point
Sub New(ByVal pt As Point)
myPoint = pt
End Sub
Public Overrides Property thePoint() As System.Drawing.Point
Get
Return myPoint
End Get
Set(ByVal value As System.Drawing.Point)
myPoint = value
End Set
End Property
End Class
End Class
Class pointHolder
Dim myPoints As New Dictionary(Of Integer, Point)
Private Class IndexedPointRef
Inherits PointRef
Dim ref As pointHolder
Dim index As Integer
Sub New(ByVal ref As pointHolder, ByVal index As Integer)
Me.ref = ref
Me.index = index
End Sub
Public Overrides Property thePoint() As System.Drawing.Point
Get
Dim mypoint As New Point(0, 0)
ref.myPoints.TryGetValue(index, mypoint)
Return mypoint
End Get
Set(ByVal value As System.Drawing.Point)
ref.myPoints(index) = value
End Set
End Property
End Class
Default Public Property item(ByVal index As Integer) As PointRef
Get
Return New IndexedPointRef(Me, index)
End Get
Set(ByVal value As PointRef)
myPoints(index) = value.thePoint
End Set
End Property
Shared Sub test()
Dim theH1, theH2 As New pointHolder
theH1(5).X = 9
theH1(9).Y = 20
theH2(12).X = theH1(9).Y
theH1(20) = theH2(12)
theH2(12).Y = 6
Dim h5, h9, h12, h20 As Point
h5 = theH1(5)
h9 = theH1(9)
h12 = theH2(12)
h20 = theH1(20)
End Sub
End Class