C# constant arrays
As you must know, there’s no such thing as C# constant arrays - http://www.google.com/search?hl=en&q=c%23+const+array
For example, the below code will not compile
const int [] constIntArray = newint [] {2, 3, 4};
On the other hand, a static readonly will compile
static readonly int [] constIntArray = new int[] {1, 2, 3};
But it’s of no use since even though cannot reassign the array itself, you can replace individual values. The readonly makes you think it cannot be changed, which is bad because you could end up wrong values at runtime.
What I needed was an array that I couldn’t re-assign at run time.
As usual, I was trying to avoid hard-coding something and in this case it was field names. I needed some way to work with field names so that even if the names or the order of the fields changed tomorrow, I could just change an enum and the constants and the rest of the code would work fine.
Of course, I could simply do this
public enum Fields
{
ItemId = 0,
ShortDescription = 1,
public class FieldNames
{
public const string ItemId = “INV_ITEM_ID”;
public const string ShortDescription = “DESCRSHORT”;
But then, that’s two sets of names for the same thing and if there’s anything I like less than hard-coding, it’s redundant code.
What I needed was something like this, which was impossible.
public enum Fields
{
ItemId = 0,
ShortDescription = 1,
public class FieldNames
{
public const string[] Names = new string[Enum.GetValues(typeof(Fields)).Length];
Names[Fields.ItemId] = “INV_ITEM_ID”;
Names[Fields.ShortDescription] = “DESCRSHORT”;
But I think I’ve found a nice workaround. It’s basically a combination of <b>Singleton class with an indexer</b> and an enum.
public enum Fields
{
ItemId = 0,
ShortDescription = 1,
public class FieldNames
{
private FieldNames()
{
}
private static FieldNames _Instance;
public static FieldNames Instance
{
// Singleton implementation
}
public string this [Fields FieldNumber]
{
get
{
switch (FieldNumber)
{
case Fields.ItemId:
return “INV_ITEM_ID”; case Fields.ShortDescription:
return “DESCRSHORT”; case Fields.CurrentItemStatus:
return “ITM_STATUS_CURRENT”; case Fields.ItemStatusEffectiveDate:
return “ITM_STATUS_EFFDT”; case Fields.DateAdded:
return “DATE_ADDED”; case Fields.LastModififedDate:
return “LAST_DTTM_UPDATE”;
// and many many more
default:
return “”;
}
}
}
}
And you can then access the field names directly in your code like this.
FieldNames.Instance[Fields.AplWaiverRequired]
like in
if ((string)OneRow[FieldNames.Instance[Fields.AplWaiverRequired]]==”Y”)
Basically, the FieldNames class acts as a constant array.
This combination does the whole job, as in
1. The values are decided at compile time and cannot be changed at runtime (Indexer FieldNames cannot be assigned to - there is no ‘set’)
2. There is absolutely no hard-coding
3. There is only one set of names (the part I like best)
Of course, the code is definitely slightly longer than if you hard-coded it or simply used constants but that’s a small price for cleaner stronger code.
From:
Sent: Wednesday, October 11, 2006 4:22 PM
To:
Subject: C# constant arrays
Just a quick update to what I’d written below.
The below method also allows me to consistently use my constant array even in ASPX files like in the asp:DataGrid below.
So basically, a field in the DB is replaced with another one tomorrow, I can change it in one place in the app and everything will be running fine.
<asp:TemplateColumn HeaderText=”ItemId”>
<ItemTemplate>
<a href=”Details.aspx?Pid=
<%#DataBinder.Eval(Container.DataItem, AplLiteComponent.FieldNamesSql.Instance[AplLiteComponent.Fields.ItemId])%>
“>
<%#DataBinder.Eval(Container.DataItem, AplLiteComponent.FieldNamesSql.Instance[AplLiteComponent.Fields.ItemId])%>
</a>
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText=”ManufacturerId”>
<ItemTemplate>
<%#DataBinder.Eval(Container.DataItem, AplLiteComponent.FieldNamesSql.Instance[AplLiteComponent.Fields.ManufacturerId])%>
</ItemTemplate>
</asp:TemplateColumn>
But there is a downside.
Server ASPX tags like DataTextField and HeaderText do not accept <% server values %>
So asp:BoundColumn can’t be used and HeaderText will have to hold the enum value temporarily till it can be replaced with a simple piece of code like this - almost the same as assigning at runtime, but a little cleaner
private void Page_Load(object sender, System.EventArgs e)
{
if (!IsPostBack)
{
foreach (DataGridColumn OneColumn in DgResults.Columns)
OneColumn.HeaderText = FieldNamesCs.Instance[(Fields)Enum.Parse(typeof(Fields), OneColumn.HeaderText)];
For example, the below code will not compile
const int [] constIntArray = newint [] {2, 3, 4};
On the other hand, a static readonly will compile
static readonly int [] constIntArray = new int[] {1, 2, 3};
But it’s of no use since even though cannot reassign the array itself, you can replace individual values. The readonly makes you think it cannot be changed, which is bad because you could end up wrong values at runtime.
What I needed was an array that I couldn’t re-assign at run time.
As usual, I was trying to avoid hard-coding something and in this case it was field names. I needed some way to work with field names so that even if the names or the order of the fields changed tomorrow, I could just change an enum and the constants and the rest of the code would work fine.
Of course, I could simply do this
public enum Fields
{
ItemId = 0,
ShortDescription = 1,
public class FieldNames
{
public const string ItemId = “INV_ITEM_ID”;
public const string ShortDescription = “DESCRSHORT”;
But then, that’s two sets of names for the same thing and if there’s anything I like less than hard-coding, it’s redundant code.
What I needed was something like this, which was impossible.
public enum Fields
{
ItemId = 0,
ShortDescription = 1,
public class FieldNames
{
public const string[] Names = new string[Enum.GetValues(typeof(Fields)).Length];
Names[Fields.ItemId] = “INV_ITEM_ID”;
Names[Fields.ShortDescription] = “DESCRSHORT”;
But I think I’ve found a nice workaround. It’s basically a combination of <b>Singleton class with an indexer</b> and an enum.
public enum Fields
{
ItemId = 0,
ShortDescription = 1,
public class FieldNames
{
private FieldNames()
{
}
private static FieldNames _Instance;
public static FieldNames Instance
{
// Singleton implementation
}
public string this [Fields FieldNumber]
{
get
{
switch (FieldNumber)
{
case Fields.ItemId:
return “INV_ITEM_ID”; case Fields.ShortDescription:
return “DESCRSHORT”; case Fields.CurrentItemStatus:
return “ITM_STATUS_CURRENT”; case Fields.ItemStatusEffectiveDate:
return “ITM_STATUS_EFFDT”; case Fields.DateAdded:
return “DATE_ADDED”; case Fields.LastModififedDate:
return “LAST_DTTM_UPDATE”;
// and many many more
default:
return “”;
}
}
}
}
And you can then access the field names directly in your code like this.
FieldNames.Instance[Fields.AplWaiverRequired]
like in
if ((string)OneRow[FieldNames.Instance[Fields.AplWaiverRequired]]==”Y”)
Basically, the FieldNames class acts as a constant array.
This combination does the whole job, as in
1. The values are decided at compile time and cannot be changed at runtime (Indexer FieldNames cannot be assigned to - there is no ‘set’)
2. There is absolutely no hard-coding
3. There is only one set of names (the part I like best)
Of course, the code is definitely slightly longer than if you hard-coded it or simply used constants but that’s a small price for cleaner stronger code.
From:
Sent: Wednesday, October 11, 2006 4:22 PM
To:
Subject: C# constant arrays
Just a quick update to what I’d written below.
The below method also allows me to consistently use my constant array even in ASPX files like in the asp:DataGrid below.
So basically, a field in the DB is replaced with another one tomorrow, I can change it in one place in the app and everything will be running fine.
<asp:TemplateColumn HeaderText=”ItemId”>
<ItemTemplate>
<a href=”Details.aspx?Pid=
<%#DataBinder.Eval(Container.DataItem, AplLiteComponent.FieldNamesSql.Instance[AplLiteComponent.Fields.ItemId])%>
“>
<%#DataBinder.Eval(Container.DataItem, AplLiteComponent.FieldNamesSql.Instance[AplLiteComponent.Fields.ItemId])%>
</a>
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText=”ManufacturerId”>
<ItemTemplate>
<%#DataBinder.Eval(Container.DataItem, AplLiteComponent.FieldNamesSql.Instance[AplLiteComponent.Fields.ManufacturerId])%>
</ItemTemplate>
</asp:TemplateColumn>
But there is a downside.
Server ASPX tags like DataTextField and HeaderText do not accept <% server values %>
So asp:BoundColumn can’t be used and HeaderText will have to hold the enum value temporarily till it can be replaced with a simple piece of code like this - almost the same as assigning at runtime, but a little cleaner
private void Page_Load(object sender, System.EventArgs e)
{
if (!IsPostBack)
{
foreach (DataGridColumn OneColumn in DgResults.Columns)
OneColumn.HeaderText = FieldNamesCs.Instance[(Fields)Enum.Parse(typeof(Fields), OneColumn.HeaderText)];
Comments
Post a Comment