I'm designing an application that requires a "location" field. The values for the location are "3241", "4112", "ND" and "TRAVEL", and I am trying to set up an enum that includes those values.
I started with
enum projectLocation {3241,4112,ND,TRAVEL};
but the values 3241 and 4112 indicated a syntax error--identifier expected--for the first value in the enum. If I understand enum correctly, that's because the above statement is looking for the value for the enum's integer indeces of 3241 and 4112. Is this a correct assumption?
I tried overriding that with the following
enum projectLocation {3241=0,4112,ND,TRAVEL};
and
enum projectLocation {3241=0,4112=1,ND=2,TRAVEL=3};
but I'm still getting the same syntax error on the 3241 value. Interestingly though, on both of these statements, there is NO syntax error on 4112, but I get can't find the namespace or name ND and ...TRAVEL
It makes sense that enum will not allow a mix of strings and integers, and I have two other enums that work fine and are only lists of string values, corroborating that theory. Is there a way to force enum to accept the numeric values as strings? I've not been able to find any references in MSDNs C# documentation.
Enums are called as named constants, so basically you give a name for some constant. Names are "identifiers" in c#, where identifier can contain numbers but first character cannot be a number.
You can add _ before that to fix this error.
enum projectLocation
{
_3241=0,
_4112=1,
ND=2,
TRAVEL=3
}
Also note the Fields, Properties Methods or whatever falls under this identifier rule mentioned above.
You can't do it exactly like you're trying to. Here's an alternative:
enum projectLocation {
L3241=3241,
L4112=4112,
ND=2,
TRAVEL=3
}
Starting them with a letter makes them valid enum identifiers, and setting their value equal to their number lets you do things like (projectLocation)3241 and get the expected L3241 value.
If you need the values to be 3241 and 4112 when serialized, include the proper attribute for your serialization approach, e.g. with Json.NET:
enum projectLocation {
[JsonProperty("3241")]
L3241=3241,
[JsonProperty("4112")]
L4112=4112,
ND=2,
TRAVEL=3
}
You would need to do something like this:
enum projectLocation { v3241, v4112, ND, TRAVEL };
or:
enum projectLocation { _3241, _4112, ND, TRAVEL };
My preference would be the use of the underscore.
C# does not allow the first character of member names to start with a number. Consider using the # character as a prefix, or some other character that conveys a meaning useful to a reader of the code as a number in isolation may not be very intuitive to a reader not familiar with the significance of 3241 in your context.
Related
I`ve got a bunch of Enums that have been generated from an XSD. They have formats like the following (enums with names, but not numeric values):
public enum MyEnum
{
/// <remarks/>
[System.Xml.Serialization.XmlEnumAttribute("001")]
Item001,
/// <remarks/>
[System.Xml.Serialization.XmlEnumAttribute("002")]
Item002,
.... // etc.
/// <remarks/>
[System.Xml.Serialization.XmlEnumAttribute("199")]
Item199,
}
What I would like is a simple way to refactor these as follows:
public enum MyEnum
{
/// <remarks/>
[System.Xml.Serialization.XmlEnumAttribute("001")]
Item001 = 1,
/// <remarks/>
[System.Xml.Serialization.XmlEnumAttribute("002")]
Item002 = 2,
.... // etc.
/// <remarks/>
[System.Xml.Serialization.XmlEnumAttribute("199")]
Item199 = 199,
}
I need this in order to parse integer values (from a config-file or a DB) into enum values. Note that the needed int values are found both in the XmlEnumAttribute, and in the enum value name itself - just not as a numeric value.
Any ideas for performing this refactoring quickly would be greatly appreciated.
Example and extra background info:
I want to do:
var myEnumValue = (MyEnum) integerFromDb;
I realize that I could probably solve this by creating a method that appends the int value of each piece of data to the string Item, and parses it to an enum using the resulting name, but that has a couple of weaknesses:
Feels like a dirty hack
Might not work properly for names like MyEnum.Item02 and MyOtherEnum.Item002
It would not allow me to refer to enum values using the integer values that are defined outside my system (i.e. this would not be in proper compliance with the rules in the XSD that my enums are based on).
You can use Visual Studio's search-and-replace feature to do this without too much trouble (note…I am assuming VS2013 here, which uses the standard .NET regex syntax; earlier versions of VS can do this also, but they use a custom regex syntax, which you can look up yourself if needed):
Open your source file. Make sure every enum value is declared identically; in particular, put a comma after even the last one.
Press Ctrl+H to show the search-and-replace UI
Enter Item(\d+), as your text to find, and Item$1 = $1, as the replacement text.
Make sure the scope is set to "Current Document".
Press Alt+A. This will replace all matches in the file.
This actually is enough to get the code to compile as you want. But you may prefer to remove leading 0 digits. You can again use the search-and-replace to do that:
Enter = 0 as the text to find, and = as the replacement text.
Press Alt+A twice (because you have at most two leading zeroes)
Finally: as far as your idea of handling it in run-time only, converting via the value name would indeed be potentially problematic, given the dependency on the exact formatting of the name. But note that you have a true parseable integer here, in the [XmlEnum] attribute.
So if you wanted to create the necessary dictionaries for converting (you wouldn't want to keep inspecting the attribute itself, as reflection is slow), you could enumerate the enum type via reflection, get the attributes for each value, parse the string found in the XmlEnumAttribute.Name property, and use that to create dictionary entries, i.e. in a Dictionary<int, MyEnum> and Dictionary<MyEnum, int> to facilitate conversion in either direction.
I've already accepted the answer by Peter Duniho, but would like to expand a little more on it here, since I used a couple of variations:
In my generated file, most of the enums were in the same file, and for some of them, then values had already been replaced. Running the "Replace All" procecure would therefore cause other problems.
Replace next
Therefore, instead of Alt + A (replace all) to replace all matches, I used Alt + R (replace next) repeatedly to loop through and replace only those matches necessary. This let me quickly loop through all my code, without messing up what was already fixed.
F3 (Find Next) can be used as in a normal search, to skip matches that should not be altered.
Leading zeros
I didn't want to remover the 0 in e.g. Item010 = 0, which would be invalid, so I used the following search term instead: = 0\d, which finds only leading zeros (i.e. zeros followed by another number).
I'm opening old C# code from my work using Reflector and I found out that there was an enum in an SQL class which looked like this:
public enum Column
{
bool,
...
}
The enum is populated with column types and it doesn't compile due it being a reserved keyword. Obviously someone was able to compile it at some point. How do I get it to compile?
Thanks!
You need to prefix with a character literal (# symbol) in order to use keywords.
MSDN (Thanks #erikH)
I have a database field (postcode) that I want to contain upper case characters, spaces and numbers. No lower case or other punctuation. I'd like to deal with that as declaratively as possible. One way would be to use a regular expression DataAnnotation to validate, [A-Z][0-9]\w (or similar - I'm not a regular expression expert, but I'm sure the right regular expression is there to be found). That would do half of what I want - it would force the user to input in uppercase, but it wouldn't convert to uppercase.
If I want to convert to uppercase there are some solutions in Stack Overflow question How can I force input to uppercase in an ASP.NET textbox?, but none of them are particularly declarative. At the moment I'm thinking of a combination of the validation and jQuery to spot anything with a class of "uppercaseonly" and convert the data, but it's a bit messy.
Am I missing anything?
CSS text-transform: uppercase?
http://www.w3schools.com/css/pr_text_text-transform.asp
UPDATE:
Try implementing a custom ModelBinder. Here's an example: http://www.agileatwork.com/custom-model-binder-in-asp-net-mvc/
Instead of AddRoles just set the property to uppercase. No need to touch your EF classes.
Why not just change the setter to store the received value as uppercase?
So, in your class object, instead of the shorthand property { get; set; } change to;
get { return this.property; }
set { this.property = value.ToUpper(); }
I have some client data that I am reading in, and I've defined an Enum for one of the values, so I can use Enum.Parse(type, somestring).
The problem is they just added a new value: "public". Is it possible to define an enum value that is also a reserved word?
I.E.:
public enum MyEnum {
SomeVal,
SomeOtherVal,
public,
YouGetTheIdea
}
If not I guess I'll be writing a parse method instead.
You can prepend a # to the variable name. This allows you to use keywords as variable names - so #public.
See here.
From the C# spec:
The prefix "#" enables the use of keywords as identifiers, which is useful when interfacing with other programming languages. The character # is not actually part of the identifier, so the identifier might be seen in other languages as a normal identifier, without the prefix. An identifier with an # prefix is called a verbatim identifier. Use of the # prefix for identifiers that are not keywords is permitted, but strongly discouraged as a matter of style.
yes, prefix the name with an #. i.e. #public
If you capitalize public to Public it won't be recognized as a keyword. Keywords are case sensitive.
As a general practice, however, it's a bad idea to use names that are keywords (even when they differ by case) as it can cause confusions, or even subtle defects if the keyword is accidentally used in place of the identifier.
It's also possible to use the # in certain contexts (like variable or member declarations) to use reserved words as non-keywords. However, it's not a common practice and should only be a means of last resort, when you can't use a different name.
So in your case you could also use #public to use the reserved word as an enum identifier.
If you chose to use #, be aware that the symbol is only used in your source code to differentiate the identifier from the reserved word. To the outside world (and in methods like Enum.Parse()), the name of the enum value is simply public.
It's not really a great idea to do this though. Instead, add a bit more info to the enum:
PublicAccess etc
In VB.Net use square braces [...] to delineate a keyword as an identifier.
Example:
Public Sub Test(ByVal [public] As String)
MessageBox.Show("Test string: " & [public])
End Sub
For VB.NET do the following:
Public Enum MyEnum As Integer
Disabled = 0
[New] = 1
[Public] = 2
Super = 4
[Error] = 5
End Enum
If I execute the following statement:
string.Compare("mun", "mün", true, CultureInfo.InvariantCulture)
The result is '-1', indicating that 'mun' has a lower numeric value than 'mün'.
However, if I execute this statement:
string.Compare("Muntelier, Schweiz", "München, Deutschland", true, CultureInfo.InvariantCulture)
I get '1', indicating that 'Muntelier, Schewiz' should go last.
Is this a bug in the comparison? Or, more likely, is there a rule I should be taking into account when sorting strings containing accented
The reason this is an issue is, I'm sorting a list and then doing a manual binary filter that's meant to get every string beginning with 'xxx'.
Previously I was using the Linq 'Where' method, but now I have to use this custom function written by another person, because he says it performs better.
But the custom function doesn't seem to take into account whatever 'unicode' rules .NET has. So if I tell it to filter by 'mün', it doesn't find any items, even though there are items in the list beginning with 'mun'.
This seems to be because of the inconsistent ordering of accented characters, depending on what characters go after the accented character.
OK, I think I've fixed the problem.
Before the filter, I do a sort based on the first n letters of each string, where n is the length of the search string.
There is a tie-breaking algorithm at work, see http://unicode.org/reports/tr10/
To address the complexities of
language-sensitive sorting, a
multilevel comparison algorithm is
employed. In comparing two words, for
example, the most important feature is
the base character: such as the
difference between an A and a B.
Accent differences are typically
ignored, if there are any differences
in the base letters. Case differences
(uppercase versus lowercase), are
typically ignored, if there are any
differences in the base or accents.
Punctuation is variable. In some
situations a punctuation character is
treated like a base character. In
other situations, it should be ignored
if there are any base, accent, or case
differences. There may also be a
final, tie-breaking level, whereby if
there are no other differences at all
in the string, the (normalized) code
point order is used.
So, "Munt..." and "Münc..." are alphabetically different and sort based on the "t" and "c".
Whereas, "mun" and "mün" are alphabetically the same ("u" equivelent to "ü" in lost languages) so the character codes are compared
It looks like the accented character is only being used in a sort of "tie-break" situation - in other words, if the strings are otherwise equal.
Here's some sample code to demonstrate:
using System;
using System.Globalization;
class Test
{
static void Main()
{
Compare("mun", "mün");
Compare("muna", "münb");
Compare("munb", "müna");
}
static void Compare(string x, string y)
{
int result = string.Compare(x, y, true,
CultureInfo.InvariantCulture));
Console.WriteLine("{0}; {1}; {2}", x, y, result);
}
}
(I've tried adding a space after the "n" as well, to see if it was done on word boundaries - it isn't.)
Results:
mun; mün; -1
muna; münb; -1
munb; müna; 1
I suspect this is correct by various complicated Unicode rules - but I don't know enough about them.
As for whether you need to take this into account... I wouldn't expect so. What are you doing that is thrown by this?
As I understand this it is still somewhat consistent. When comparing using CultureInfo.InvariantCulture the umlaut character ü is treated like the non-accented character u.
As the strings in your first example obviously are not equal the result will not be 0 but -1 (which seems to be a default value). In the second example Muntelier goes last because t follows c in the alphabet.
I couldn't find any clear documentation in MSDN explaining these rules, but I found that
string.Compare("mun", "mün", CultureInfo.InvariantCulture,
CompareOptions.StringSort);
and
string.Compare("Muntelier, Schweiz", "München, Deutschland",
CultureInfo.InvariantCulture, CompareOptions.StringSort);
gives the desired result.
Anyway, I think you'd be better off to base your sorting on a specific culture such as the current user's culture (if possible).