How can I use a reserved keyword as an identifier in my JSON model class?
I would suggest to go different way. Keep your C# object model as much standard as possible (I wouldn't use @
sign and C# keywords
as property name).
We can separate the serialized (JSON) world and C# objects - just by using the Json.NET features.
One of the simpliest to use is decoration with Attribute:
[JsonProperty(PropertyName = "default")]
public string DefaultValue { get; set; }
In this case we have to reference Newtonsoft.Json in the project. If it must be POCO, we can introduce CustomResolver
derrived from DefaultContractResolver
and define these conversions there...
But separation of concern in this case is a bit more pure solution, I would say
EDIT: JSON Contract Resolver draft (see comments)
Important NOTE: Newtonsoft.Json is part of the Web API. Not only it is an open source, but even MS team bet on that as a core JSON serializer.
1) Newtonsoft.Json (as a part of the Web.API) is already installed in your solution. So you do not have to downloaded (nuget) separately. It would always be in your packages
folder. So, to use the attribute is just adding the reference. It is there...
2) There is a small draft how to do the attribute stuff, while keeping the POCO. As I've tried explain here: POCO's, behavior and Peristance Igorance, to keep POCO (e.g. we do profit from layered Architecture with NHibernate on a data layer), we can replace attributes with a Contract Resolver
. Our POCO library does not have to reference anything
We just have to do extend the service layer:
public class MyResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(
MemberInfo member,
MemberSerialization memberSerialization)
{
var jProperty = base.CreateProperty(member, memberSerialization);
var propertyInfo = member as PropertyInfo;
if (propertyInfo == null)
{
return jProperty;
}
// just adjust in case if Property name is DefaultValue
var isDefaultValueProeprty =
propertyInfo.Name.Equals("DefaultValue");
if(isDefaultValueProeprty)
{
jProperty.PropertyName = "default";
}
return jProperty;
}
...
This way we've provided the same information to serailizer as with the [JsonPropertyAttribute]
.
Now, we just have to use it. There are many ways (e.g. global) but we can do it for a controller only:
protected override void Initialize(HttpControllerContext context)
{
base.Initialize(context);
var jSettings = context.Configuration.Formatters.JsonFormatter.SerializerSettings;
jSettings.ContractResolver = MyResolver;
}
Access to an attribute of a class when the name is a reserved keyword- Python
Peeking through the code of the API you are referencing, it looks like reserved words the convention for their classes is to prefix it with a leading _
(looking here)
So try using item.via._from
, the _from is a valid identifier.
Could also be best to call the to_dict
or even actual lower-level __dict__
on the object and access it by string, but I think the first should work:
x = item.via._from.id
x = item.to_dict()["via"]["from"]["id"]
# or worst case…
x = item.via.__dict__["from"].id
Creating Java Object with reserved keywords as variable name
If you use GSON for parsing you can name your members as you want and annotate them for mapping.
@SerializedName("abstract")
private String abstractText;
Using reserved words as property names, revisited
In ECMAScript, starting from ES5, reserved words may be used as object property names "in the buff". This means that they don't need to be "clothed" in quotes when defining object literals, and they can be dereferenced (for accessing, assigning, and deleting) on objects without having to use square bracket indexing notation.
That said, reserved words may still NOT be used as identifier names. This is stated quite unambiguously in the spec and is stated somewhat emphatically here (if you don't want your eyes to bleed by having to read the actual language spec)...
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Reserved_Words
The following are keywords and may not be used as variables,
functions, methods, or object identifiers, because ECMAScript
specifies special behavior for them:
Do reserved words need to be quoted when set as property names of JavaScript objects?
ECMAScript 5+
No, quotes were not needed since ECMAScript 5. Here's why:
As mentioned in your post, from the ECMAScript® 5.1 Language Specification:
7.6 Identifier Names and Identifiers
Identifier Names are tokens that are interpreted according to the grammar given in the “Identifiers” section of chapter 5 of the Unicode standard, with some small modifications. An
Identifier
is anIdentifierName
that is not aReservedWord
(see 7.6.1).[...]
Syntax
Identifier ::
IdentifierName but not ReservedWord
By specification, a ReservedWord
is:
7.6.1 Reserved Words
A reserved word is an
IdentifierName
that cannot be used as anIdentifier
.Syntax
ReservedWord ::
Keyword
FutureReservedWord
NullLiteral
BooleanLiteral
This includes keywords, future keywords, null
, and boolean literals. The full list is as follows:
7.6.1.1 Keywords
break do instanceof typeof
case else new var
catch finally return void
continue for switch while
debugger function this with
default if throw
delete in try
7.6.1.2 Future Reserved Words
class enum extends super
const export import
7.8.1 Null Literals
null
7.8.2 Boolean Literals
true
false
The above (Section 7.6) implies that IdentifierName
s can be ReservedWord
s, and from the specification for object initializers:
11.1.5 Object Initialiser
[...]
Syntax
ObjectLiteral :
{ }
{ PropertyNameAndValueList }
{ PropertyNameAndValueList , }
Where PropertyName
is, by specification:
PropertyName :
IdentifierName
StringLiteral
NumericLiteral
As you can see, a PropertyName
may be an IdentifierName
, thus allowing ReservedWord
s to be PropertyName
s. That conclusively tells us that, by specification, it is allowed to have ReservedWord
s such as class
and var
as PropertyName
s unquoted just like string literals or numeric literals.
ECMAScript <5
To go more in depth as to why this wasn't allowed in previous versions before ES5, you have to look at how PropertyName
was defined. Per the ECMAScript® 3 Language Specification:
PropertyName :
Identifier
StringLiteral
NumericLiteral
As you can see, PropertyName
was an Identifer
- not an IdentifierName
, thus leading to the inability for ReservedWord
s as PropertyName
s.
How is this Java project using the language reserved words as identifiers?
While reserved words may not occur in Java source code, they are permitted in compiled Java code. Some code obfuscation tools can make use of this to make decompiling harder. For instance, ProGuard provides the following option:
-obfuscationdictionary filename
Specifies a text file from which all valid words are used as obfuscated field and method names. By default, short names like 'a', 'b', etc. are used as obfuscated names. With an obfuscation dictionary, you can specify a list of reserved key words, or identifiers with foreign characters, for instance. White space, punctuation characters, duplicate words, and comments after a# sign are ignored. Note that an obfuscation dictionary hardly improves the obfuscation. Decent compilers can automatically replace them, and the effect can fairly simply be undone by obfuscating again with simpler names. The most useful application is specifying strings that are typically already present in class files (such as 'Code'), thus reducing the class file sizes just a little bit more. Only applicable when obfuscating.
So if you feed this a list with Java identifiers (such as this one) you end up with a class file that causes syntax errors if decompiled. Of course, you can simply rename the variables to fix these compilation errors (for instance by using ProGuard yourself before decompiling), so this is only a minor inconvenience.
Deserializing url-encoded-form-data with reserved word as variable name
The trick is to tell the compiler to not treat that name as the reserved keyword event
, and you do that with an at-sign, like this:
public string @event { get; set; }
Now, you might think this will be similar to using an underscore but that is not correct. The at-sign will actually not become part of the event name, it's just there to tell the compiler to not treat the next word as a reserved keyword, and instead treat it as an identifier.
Also note that everywhere you want to refer to this property, you likely have to keep using the at-sign prefix or that reference will not compile either.
Here's an example:
void Main()
{
Console.WriteLine(nameof(@event));
Console.WriteLine(nameof(_event));
}
public string @event { get; set; }
public string _event { get; set; }
Will output:
event
_event
object to deserialize has a C# keyword
Try using the [DataContract(Name = "@event")]
attribute on the relevant property. Then it will (de)serialize correctly, and you can rename the property so that it compiles.
Related Topics
Is There a Good Way to Convert Between Bitmapsource and Bitmap
Showing a Windows Form on a Secondary Monitor
How to Implement Real Time Data for a Web Page
A Generic Error Occurred in Gdi+ in Bitmap.Save Method
Reliably Stop System.Threading.Timer
Dynamically Access Table in Ef Core 2.0
File I/O with Streams - Best Memory Buffer Size
How to Convert String to Double with Proper Cultureinfo
What Does "Datetime" Mean in C#
How Big Is an Object Reference in .Net
Why Does "Int[] Is Uint[] == True" in C#
Why Is the 'This' Keyword Required to Call an Extension Method from Within the Extended Class
Fastest Method to Remove Empty Rows and Columns from Excel Files Using Interop
Serialize Dictionary as Array (Of Key Value Pairs)
C# - Get a List of Files Excluding Those That Are Hidden
Differencebetween Declarative and Imperative Paradigm in Programming