Why is this .NET enumeration allowed to have a comma in the last field?
Does this have any special meaning?
[FlagsAttribute]
public enum DependencyPropertyOptions : byte
{
Default = 1,
ReadOnly = 2,
Optional = 4,
DelegateProperty = 32,
Metadata = 8,
NonSerialized = 16,
}
It has no special meaning, just the way the compiler works, it's mainly for this reason:
[FlagsAttribute]
public enum DependencyPropertyOptions : byte
{
Default = 1,
ReadOnly = 2,
Optional = 4,
DelegateProperty = 32,
Metadata = 8,
NonSerialized = 16,
//EnumPropertyIWantToCommentOutEasily = 32
}
By comment request: This info comes straight out of the C# Specification (Page 355/Section 17.7)
Like Standard C++, C# allows a trailing comma at the end of an array-initializer. This syntax provides flexibility in adding or deleting members from such a list, and simplifies machine generation of such lists.
Also (to Nick Craver post) its much easier to add new enumerations.
This behaviour appropriate not uniquely to enums. Consider following:
var list = new int[] { 1, 2, 3, };
One other reason: It makes it easier to code gen.
I know that it is an old topic but, another approach that would make sense for this issue is for code versioning systems.
Consider the following example:
//version 1
var myArray = {
"item 1",
"item 2"
};
//version 2
var myArray = {
"item 1",
"item 2", //will be considered a change, it may be considered an erroneous approach
"item 3"
}
Now consider this approach:
//version 1
var myArray = {
"item 1",
"item 2",
};
//version 2
var myArray = {
"item 1",
"item 2", //will not be considered a change, it may be considered an erroneous approach too, but, means that the code wasn't changed intrinsically
"item 3",
};
Anyhow, both approaches may be considered incorrect or correct depending on the situation. I particularly prefer the second approach that makes much more sense when dealing with code versioning systems.
Anyway hope this helps.
Why add trailing commas
Why you should take advantage of this feature when writing code manually?
The resultant patches have less lines affected. This makes them easier to read and review.
Automatic merge and conflict resolution are more accurate because there isn't extra noise to confuse the algorithm.
Examples
Without trailing comma (okay)
Example of adding a line when the previous developer didn't leave a trailing comma:
## -119,7 +119,8 ## namespace SomeApp.Example
{
NameTitle = contact.NameTitle,
GivenName = contact.GivenName,
- FamilyName = contact.FamilyName
+ FamilyName = contact.FamilyName,
+ ProperName = contact.ProperName
},
ContactTelephone1 = contact.ContactTelephone1,
ContactType = contact.ContactType,
Without trailing comma (better)
Example of adding a line when the previous developer left a trailing comma:
## -122,2 +122,3 ## namespace SomeApp.Example
FamilyName = contact.FamilyName,
+ ProperName = contact.ProperName,
},
Note there is one line added in the latter vs one removed and two added. This is much easier for human and machine alike to deal with.
Why did they add it to C#?
As for why it is allowed, as per other answers:
The C# Specification (Page 355/Section 17.7) states:
Like Standard C++, C# allows a trailing comma at the end of an array-initializer. This syntax provides flexibility in adding or deleting members from such a list, and simplifies machine generation of such lists.
This applies to array initializers, object initializers and enums.
Related
I have enums GroupTypes which I add to Types property.
There can be either Up/Down or both Up And Down types.
This is my code:
public enum GroupTypes: int {
Down = 0,
Up = 1,
}
[Column("types")]
[JsonProperty(PropertyName = "types")]
public GroupTypes[] Types {
get;
set;
}
// e.g.
var group = new Group() {
Name = "Group",
Types = new GroupTypes[] {
GroupTypes.Up
},
OrganizationId = Organization.Id,
};
However when I post them to database I get 500 error.
It seems correct to me and I am not sure what goes wrong.
In my database the type for this column is: "types" int4[] NULL and I expect them to be saved as array ( [0,1] or [1] or [0])in the database . What I am misisng here?
Before adding types, post method worked fine so I am assuming they are the problem but it seems like I define them correctly. I am using DBeaver and PostgreSQL
It is usually a good idea to use Flags enum & bitwise operations
Your case should be like this:
[Flags]
public enum GroupTypes:
{
None = 0,
Down = 1,
Up = 2,
DownAndUp = Down | Up
}
As a result, You need to save single value only instead of list of values.
If I were you, I wouldn't use an array to reflect that model. It'd be much better to use Up, Down and Both, for instance, otherwise you have to deal with the fact that it could be [1], [0], [1, 0], [0, 1], four combinations for the three states you need to present.
Also, this would map more elegantly to a database. In fact, I pretty much would use a character or even a whole string to represent that data, which gives more semantic value in the database (you already calling the column type, which is pretty generic.
public enum Types : char
{
Down = 'D',
Up = 'U',
Both = 'B',
}
With all that said, I haven't answered your question, because I need more information on the error you're getting and how you are communicating with the database.
I'm using ASP.NET Core 2.1. I have settings in appsettings.json and I bind them to classes using the options pattern. I want to override some of them in appsettings.Production.json.
Overriding is supported according to the docs, and works for me generally.
But it doesn't work for arrays.
appsettings.json:
"MySectionOuter": {
"MySectionInner": [
{
"foo": "1",
"bar": "2",
"baz": "3"
},
{
"foo": "a",
"bar": "b",
"baz": "c"
}
]
}
My overrides in appsettings.Production.json
"MySectionOuter": {
"MySectionInner": [
{
"bar": "4",
},
{
"baz": "d"
}
]
}
However that doesn't work - it adds rather than replaces.
I read that the array is syntactic sugar for a key-value store. So I also tried this:
"MySectionOuter": {
"MySection:1": {
"bar": "4",
},
"MySection:2": {
"baz": "b",
}
}
But that also doesn't work.
What is the correct syntax?
UPDATE
The comments show I haven't explained properly. What I want is like this:
During development:
element1: foo=1
element1: bar=2
element1: baz=3
element2: foo=a
element2: bar=b
element2: baz=c
During production:
element1: foo=1
element1: bar=2
element1: baz=4 // this was changed
element2: foo=a
element2: bar=b
element2: baz=d // this was changed
In fact, there are no arrays there when the configuration is built. It's just a key-value pair dictionary. So you end up with string keys, something like
"mysectionouter:mysectioninner:0:foo" = 1.
So when in your config you define an array, the following happens:
appsettings.json:
"mysectionouter:mysectioninner:0:foo" = 1
"mysectionouter:mysectioninner:0:bar" = 2
appsettings.production.json:
"mysectionouter:mysectioninner:0:bar" = new1
result:
foo = 1
bar = new1
So it's just index-based, and next configuration just overrides a key. In your second example, you achieve nothing but changing the index. Representation would be:
"mysectionouter:mysectioninner:1:bar" = new1
So back to your question: arrays are tricky in appsettings, and though supported, are generally hard and not intuitive to use.
By index you may get a weird merge of two not related objects, if you define different sets of settings in your files, like settings A and B in the first config, and C in second, you will get C and B in the result, and you likely don't want to have B at all. Worse still, you can get a mix of A and C if you define only some fields of each object.
I'd recommend using some other files for storing this kind of information. You can also break in the debugger just where the configuration is loaded and see for yourself how these keys are build to get more insight.
According to this blog post: https://www.paraesthesia.com/archive/2018/06/20/microsoft-extensions-configuration-deep-dive/
It's not possible to remove configuration items with a provider.
You can add configuration at override time, but you can’t remove things. The best you can do is override a value with an empty string.
Instead you should only fill as little information as needed in the appsettings.config and fill the appropriate settings in a more specialized settings file. E.g. appsettings.Development.config or your appsettings.Production.config. Or as suggested in the blog post:
Since you can’t remove things, specify as little configuration as possible and behave correctly using defaults in your code when configuration isn’t there.
I was actually having a similar issue in dotnet 6, when trying to merge arrays from multiple appsettings, when I stumbled across this thread.
The solution was actually way simpler then thought.
Microsoft.Extensions.Configuration merges arrays through the index:
{ foo: [1, 2, 3] } + { foo: [4, 5] } = { foo: 4, 5, 3 }
But we want to be able to declare which entries override others and which ones should be added to the list. And we do this by declaring a GUID as dictionary key instead of an array.
{
"foo": {
"870622cb-0372-49f3-a46e-07a1bd0db769": 1,
"cbb3af55-94ea-41a5-bbb5-cb936ac47249": 2,
"9410fcdc-28b3-4bff-bfed-4d7286b33294": 3
}
}
+
{
"foo": {
"cbb3af55-94ea-41a5-bbb5-cb936ac47249": 4,
"1c43fa78-b8db-41f8-809d-759a4bc35ee2": 5,
}
}
=
{
"foo": {
"870622cb-0372-49f3-a46e-07a1bd0db769": 1,
"cbb3af55-94ea-41a5-bbb5-cb936ac47249": 4, /*2 changed to 4 because key equals*/
"9410fcdc-28b3-4bff-bfed-4d7286b33294": 3
"1c43fa78-b8db-41f8-809d-759a4bc35ee2": 5, /*while 5 added to the list*/
}
}
This may seem inconventient at first, because one would think, that
((IConfiguration)config).GetSection("foo").Get<int[]>();
Throws some kind of invalid type exception, since a Guid is not what we know as array index.
But it can actually (implicitly!) return the merged "foo" section above as int[].
This question already has answers here:
Non-unique enum values
(8 answers)
Closed 9 years ago.
In .NET can you have multiple enum values for the same integer?
eg.
public enum PersonGender
{
Unknown = 0,
Male = 1,
Female = 2,
Intersex = 3,
Indeterminate = 3,
NonStated = 9,
InadequatelyDescribed = 9
}
In C#, this is allowed, as per the C# Language Specication, version 4. Section 1.10 Enums doesn't explicitly mention the possibility but, later on in section 14 Enums, 14.3, we see:
Multiple enum members may share the same associated value. The example
enum Color {
Red,
Green,
Blue,
Max = Blue
}
shows an enum in which two enum members - Blue and Max - have the same associated value.
That works fine. There is absolutely nothing wrong with the code you posted. It compiles just fine and works in code, with the caveat that
PersonGender.NonStated == PersonGender.InadequatelyDescribed
I found this StackOverflow post related to this question. I think there is a very sensible discussion of how this works. Non-unique enum values
Now, I might also add that it is my opinion this would be an ambiguous (and therefore improper) use of an enum. It's important to write code that makes sense to someone else reading it, and in this case, I would be put off by this enum.
I would suggest that an enum would not be a right thing to use in your context instead you can use create a class and methods which can resolve your purpose. Something like this in your class:-
class A
{
static readonly ABCD= new Dictionary<int,string>
{
{ 1, "X" },
{ 2, "X" },
{ 3, "Y" }
{ 4, "Y" }
}
}
Was surprised to see that a C# Enum definition seems to allow an extra comma at the end (at least in VS2010).
e.g. :
public enum EnumTest1
{
Abc,
Def,
}
i.e. there is a comma at the end of "Def".
Just wondering if this is allowed by design, or is an oversight.
(This might be good to know, because if it is a bug, there may be no guarantees that code like the above will compile in future versions of C#).
It is allowed by design. Similarly, you can have trailing commas in initializers as well. For example:
var ints = new[] { 2, 3, 4, 3, };
var obj = new SomeClass { Prop1 = "foo", Prop2 = "bar", };
I think that allowing trailing commas makes creating auto-generated code much easier because you don't have to add last-in-the-list logic when outputting a list in your code.
I have a marital status field in a database with numbers each representing a marital status in a different table. The first table has numbers 1, 3, 4:
1 = single
3 = married
4 = divorced
The second has the values:
single
married
divorced
I need an if statement as follows: if the table field returns the value 1 I want to write the message 'single', if 3 'married' and if 4 'divorced' (using Response.Write).
Rather than write an "if" statement in C#, why not just perform a join in the database to retrieve the text as part of the database query?
You can write if else, or case statement, but easier to just use array for such a small list
string[] maritalStatus = new string[] { "", "Single", "", "Married", "Divorced"};
Response.Write (maritalStatus[dbValue]);
Another option would be to declare an enum that maps to your values like this:
enum RelationshipStatus
{
Single = 1,
Married = 3,
Divorced = 4
}
Then you can just call the ToString method of the variable containing your enum value. Note that you'll need to cast the integer value from your SQL table to the enum type.
The advantage of this approach is that you can eliminate the conditional if statement entirely and I think the result is much more readable. The disadvantage is that it won't be easy to localize to other languages (translations) if you need to.
string GetStatus(int StatusCode)
{
return StatusCode == 1 ? "single" : StatusCode == 3 ? "married" : "divorced";
}
BTW there is usually no good reason to normalize this far. Performance would be better if you stored the actual status in the table and the amount of disk space is negligible.
Edit: #jon's idea is probably better than this function
Perhaps an Enum would be the most elegant approach?
public enum MaritalStatus
{
Single = 1,
Married = 3,
Divorced = 4
}
Then you can simply use Enum.GetName() and Enum.Parse() to convert between string, int and MaritalStatus objects. This may also provide you with a more elegant solution in some of your other business logic.
There are number of different ways to do that, good and bad ways
If you can join the tables in query - there's one good way
You could use SQL-CASE in procs
You could switch-case/if in middle tier/C# code.
You could create enums and type cast
like
`
public enum MaritalStatus
{
Single = 1,
Married = 3,
Divorced = 4
}
MaritalStatus status = (MaritalStatus) 4;
Console.WriteLine(status);
`
and so on