It sounds like you're taking a very OOP approach to this problem, when really you should be taking a more functional approach (just the approach - we're not going "all-in" here - we're basically just applying functions to buffers).
Instead of a cube
class (reference type) with a constructor that gets "created", simply have a cube
struct (value type) with a very small memory footprint. This could be as simple as an
int that indicates what kind of cube it is. The important thing is to, like an integer, have a "zero" value that represents an empty space.
Then create an array of these. For simplicity you can use a 3D array. Later on you might want to consider a 1D array (slightly faster in .NET) and trying to read through it while touching as little memory as possible. But for now this will do - it is far better than allocating thousands of cube objects flung all over heap memory!
The position of each cube is implicitly defined by its position in the array.
Then, taking a functional approach, you transform that "cube" data into "vertex" data for a given chunk (or the whole world, if it's small enough). A method to do that transformation might have code that looks a little something like this:
for(int y = 0; y < height; y++)
for(int x = 0; x < width; x++)
for(int z = 0; z < depth; z++)
if(x-1 >= 0 && cubes[x-1, y, z])
AddFace(x, y, z, Face.Left);
if(x+1 < width && cubes[x+1, y, z])
AddFace(x, y, z, Face.Right);
if(z-1 >= 0 && cubes[x, y, z-1])
AddFace(x, y, z, Face.Back);
if(z+1 < depth && cubes[x, y, z+1])
AddFace(x, y, z, Face.Front);
if(y-1 >= 0 && cubes[x, y-1, z])
AddFace(x, y, z, Face.Bottom);
if(y+1 < depth && cubes[x, y+1, z])
AddFace(x, y, z, Face.Top);
This takes advantage of the fact the cube data is stored in a spatially meaningful way.
AddFace as an exercise. But basically it should append appropriate vertices and indices to a
List of faces for the whole chunk. Which you'd then use to
SetData() to your chunk's
(As mentioned in comments in our discussion over here, you can save yourself the copying that
ToArray() does by using an array directly, instead of a
List, and manually managing your count and capacity. Take a look at the code in this answer)