Class for Conway's Game of Life in C#
The first bad thing you do is a lot of string concatenations like


_outputGrid += "1";



which cause many memory reallocations. Since during one game grid size is a constant number you can save it at the constructor, and then just create array for result and set its elements by index.

_outputGrid = new char[_gridSize * _gridSize];
...
_outputGrid[currentIndex] = '0';


At the end of the CalculateNextGrid method convert this array to string and return it:

return new string(_outputGrid);




I suggest to use array of bool's as internal storage for result instead of a string. In my opinion true and false represent the state of a cell (alive or dead) more clearly. You can even use array of enum values like:

public enum CellState
{
    Alive,
    Dead
}

_outputGrid[currentIndex] = CellState.Alive;


You can go further and create method like:

private void ReviveCell(int index) =&gt; _outputGrid[index] = CellState.Alive;




It would be better to extract magic conditions to some methods like:

private static bool ShouldBeDeadByUnderpopulation(int count) =&gt; count &lt; 2;

private static bool ShouldBeDeadByOverpopulation(int count) =&gt; count &gt; 3;


and so on.

And instead of condition like


if (inputGrid[currentIndex + _up    + _right]   == '1')



use methods too

if (IsAlive(value))


With all these changes your code will look like a story where all is clear :)

if (IsAlive(currentCell))
{
    if (ShouldBeDeadByUnderpopulation(_cellCount ) ||
        ShouldBeDeadByOverpopulation(_cellCount))
    {
        KillCell(currentIndex);
    }
    else
    {
        // Note that this code is redundant since cell is alive at the moment
        ReviveCell(currentIndex);
    }
}