My personal preference would be making the array two rows and two columns wider, so you would get a border around the board. So a board of 10x16 mines would actually be an array of 12x18. All (0,Y), (11,Y), (X, 0) and (X, 17) values would then hold CellState.Border, meaning that you don't check if that cell has any mines. Your active board would be from (1,1) to (10, 16) which is also nice in your coordinate system!
It does mean that you'd have to check if Board[X,Y] is set to CellState.Border, though. If yes, then don't count mines! Ignore it... Otherwise, values of X-1, X+1, Y-1 and Y+1 would always be in range as those values would go from (0,0) to (11,17).
It's a simple trick that allows you to avoid adding if-statements. Of course, you could always check if the values you're asking for are within the range or not.
My nutty mind is now thinking about a way to avoid the many if-statements that you're already using. But as I don't know how experienced you are with C#, I'm avoiding any more elegant solutions that would also be a bit complex to understand. However, I suggest that you take a slightly different approach!
You see, you're calculating the mine count for each cell. However, your array could already hold the correct mine counts once you place the mines! You are placing an N amount of mines on the board so for every mine you place, you immediately increase the mine count for all surrounding cells. This means that you don't need any if-statements to check the count. You already know the count! But it also means the Board array needs a bit more data than just a CellState value. You could create a Cell class that has a CellState property, a MineCount property and a Visited property. So initially, all cells would have a MineCount value of 0 and for every mine you place, all surrounding cells get their MineCount increased by one.
Won't solve the range exception, though. For that, you actually have to check if coordinates are within the range or not, or add the border around the array as I've mentioned.
As I said, I don't know how experienced you are, but for a more advanced solution, you might want to create a function:
public CellState GetCellState(int posY, int posX)
{
if (posX < 0) return CellState.Invalid;
if (posY < 0) return CellState.Invalid;
if (posX >= MaxX) return CellState.Invalid;
if (posY >= MaxY) return CellState.Invalid;
return Board[posY, posX];
}
This assumes you have the width and height of the board stored in the properties MaxY and MaxX. But this would allow you to rewrite your code as:
public int GetMineCount(int posY, int posX)
{
int count = 0;
if (GetCellState(posY-1, posX-1) == CellState.Mine)
count++;
if (GetCellState(posY-1, posX) == CellState.Mine)
count++;
if (GetCellState(posY-1, posX+1) == CellState.Mine)
count++;
if (GetCellState(posY, posX-1) == CellState.Mine)
count++;
if (GetCellState(posY, posX+1) == CellState.Mine)
count++;
if (GetCellState(posY+1, posX-1) == CellState.Mine)
count++;
if (GetCellState(posY+1, posX) == CellState.Mine)
count++;
if (GetCellState(posY+1, posX+1) == CellState.Mine)
count++;
return count;
}
Now the single function would check if each cell is within the proper range or not. And those four if-statements could be consolidated into one, but I wrote it this way for clarity. Your CellState enumeration would need to contain an "Invalid" value now, though.
It would still not be my preferred method, though. But the solution I'm thinking off is a bit complex to explain and would not involve an array... And I would calculate MineCount when I place mines, not afterwards...