Handling Excel column letter index as struct I've designed a little struct that should help me deal with Excel columns in terms when the letter index is used. The idea is to use the struct implicitly most of the time for iterations over Excel columns etc.

The struct works in the cases i've intended it to. However, on the one hand, I'm not sure if it isn't a little over the top for a struct and i should rather use a class. On the other hand I was a little surprised why the struct did actually work implicitly when combining it with an integer and assigning it to a string value like this

int rowIndex = 1;
ExcelColumn column = 1;
string cellId = column + rowIndex.ToString(); 


results in the string being assigned to 


  A1


So my questions are: 


Why is that the case? 
Is the struct properly designed for its purpose?


Below is the code for the struct:

public struct ExcelColumn
{
    #region Constants
    private const int MAX_COLUMN_COUNT = 16384;
    #endregion

    #region Fields
    private readonly int _value;
    #endregion

    #region Constructors
    public ExcelColumn(int columnIndex)
    {
        if (columnIndex &lt; 1) 
            throw new IndexOutOfRangeException("Index below 1 not allowed.");
        if (columnIndex &gt; MAX_COLUMN_COUNT) 
            throw new OverflowException("Max Column number exceeded");

        _value = columnIndex;
    }
    #endregion

    #region Methods
    private string GetValue()
    {
        string value = "";
        int val = _value - 1;
        do
        {
            value = Convert.ToChar(65 + val % 26) + value;
            val = (val - val % 26) / 26 - 1;
        }
        while (val &gt;= 0);
        return value;
    }
    public override string ToString()
    {
        return GetValue();
    }
    #endregion

    #region Operators
    public static ExcelColumn operator +(ExcelColumn x, ExcelColumn y)
    {
        return new ExcelColumn(x._value + y._value);
    }
    public static ExcelColumn operator +(ExcelColumn x, int y)
    {
        return new ExcelColumn(x._value + y);
    }
    public static ExcelColumn operator +(int x, ExcelColumn y)
    {
        return new ExcelColumn(x + y._value);
    }
    public static ExcelColumn operator ++(ExcelColumn x)
    {
        return new ExcelColumn(x._value + 1);
    }

    public static ExcelColumn operator -(ExcelColumn x, ExcelColumn y)
    {
        return new ExcelColumn(x._value - y._value);
    }
    public static ExcelColumn operator -(ExcelColumn x, int y)
    {
        return new ExcelColumn(x._value - y);
    }
    public static ExcelColumn operator -(int x, ExcelColumn y)
    {
        return new ExcelColumn(x - y._value);
    }
    public static ExcelColumn operator --(ExcelColumn x)
    {
        return new ExcelColumn(x._value - 1);
    }

    public static implicit operator ExcelColumn(int x)
    {
        return new ExcelColumn(x);
    }
    public static explicit operator int(ExcelColumn x)
    {
        return x._value;
    }
    #endregion

    #region Properties
    public string Value { get { return GetValue(); } }
    public int Index { get { return _value; } }
    #endregion
}
Why is that the case?


You need to know what the string + operator does under the covers - it calls String.Concat.

So when you do this:

var someString = aString + anObject;


We get this:

var someString = string.Concat(aString, anObject);


Let's look at the IL for your example:

C#

void Main()
{
    int rowIndex = 1;
    ExcelColumn column = new ExcelColumn(1);
    string cellId = column + rowIndex.ToString(); 
}


IL

IL_0000:  nop         
IL_0001:  ldc.i4.1    
IL_0002:  stloc.0     // rowIndex
IL_0003:  ldloca.s    01 // column
IL_0005:  ldc.i4.1    
IL_0006:  call        UserQuery+ExcelColumn..ctor
IL_000B:  ldloc.1     // column
IL_000C:  box         UserQuery.ExcelColumn
IL_0011:  ldloca.s    00 // rowIndex
IL_0013:  call        System.Int32.ToString
IL_0018:  call        System.String.Concat
IL_001D:  stloc.2     // cellId
IL_001E:  ret        


You can see that your ExcelColumn (column) is being boxed to an object and passed to String.Concat.

So your question is really: why does this work?

string cellId = string.Concat(column, rowIndex.ToString()); 


Answer: because column.ToString() is being called in string.Concat.

Hmmm... I hope that makes sense.



Time to review your code.

Get rid of the regions. They're almost always pointless and you certainly don't need a region around a single constant.

Constants are named PascalCase in C#. MAX_COLUMN_COUNT should be MaxColumnCount.

I think it would be better to store the string representation at creation rather than computing it each time it's needed.

Structs always have a default constructor which means you have a bug.

new ExcelColumn().ToString() // @