patterncsharpMinor
Handling Excel column letter index as struct
Viewed 0 times
handlingstructexcelcolumnletterindex
Problem
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
results in the
A1
So my questions are:
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 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 >= 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)
{
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 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 >= 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)
{
Solution
Why is that the case?
You need to know what the string
So when you do this:
We get this:
Let's look at the IL for your example:
C#
IL
You can see that your
So your question is really: why does this work?
Answer: because
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
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.
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: retYou 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() // @Code Snippets
var someString = aString + anObject;var someString = string.Concat(aString, anObject);void Main()
{
int rowIndex = 1;
ExcelColumn column = new ExcelColumn(1);
string cellId = column + rowIndex.ToString();
}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: retstring cellId = string.Concat(column, rowIndex.ToString());Context
StackExchange Code Review Q#159873, answer score: 2
Revisions (0)
No revisions yet.