-
Notifications
You must be signed in to change notification settings - Fork 646
Conversation
} | ||
} | ||
|
||
return new string(chars); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/cc @JamesNK
return value; | ||
} | ||
|
||
if (!char.IsUpper(value[0])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we generally just dealing with things that are valid C# identifiers? or does this need to camel case arbitrary strings?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to have the assumption that the input is always already a PascalCase or camelCase string
For example, some cases I'm not really sure of the expected output:
foo_Bar
ThisIsXML
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK looks like this is addressed below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, the whole notion of camelcasing is more subjective than first appears. There are plenty of strings where people would disagree about what the expected camelcase verson is, and different libraries do produce different output in practice.
My goal in this case was, for the subset of cases we care about (incoming string is a member identifier), to produce the same result as Json.NET. That's to make it easier for anyone who wants to "grow up" to Json.NET after starting with the built-in utility, or who uses Json.NET on the server and expects their client code to work like other .NET clients.
{ | ||
internal static class CamelCase | ||
{ | ||
public static string ToCamelCase(this string value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we make this not an extension method? It's used in like 4 places 😆
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, fair point. Will do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -143,6 +201,38 @@ public void SupportsInternalCustomSerializer() | |||
Assert.Equal("{\"key1\":\"value1\",\"key2\":123}", json); | |||
} | |||
|
|||
// Test cases based on https://github.com/JamesNK/Newtonsoft.Json/blob/122afba9908832bd5ac207164ee6c303bfd65cf1/Src/Newtonsoft.Json.Tests/Utilities/StringUtilsTests.cs#L41 | |||
// The only difference is that our logic doesn't have to handle space-separated words, | |||
// because we're only use this for camelcasing .NET member names |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK so that's the answer to my question from earlier then 👍
break; | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since the result of camel casing is cached, is there much value in doing perf optimizations here? This only runs once per member per type right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree the value is limited. But it wasn't difficult to implement and doesn't add a lot of complexity. The main benefit vs the Json.NET implementation is that this version only does one IsUpper
check per character rather than two. But I agree it's a super-minor benefit.
if (string.IsNullOrEmpty(value)) | ||
{ | ||
return value; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this considered invalid input since only we're calling this, and only for valid member names?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. Debatable.
If we were to reject ""
, then I think we'd at least have to rename this to CamelCaseDotNetMemberName
because it couldn't call itself a general camelcaser. The existing implementation, even without doing anything about spaces, I think fits a reasonable definition of a general camelcase implementation.
Since it's internal anyway I'd rather not get hung up on this. Let me know if you feel strongly about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK on more consideration I will be more explicit about limiting the scope to .NET identifiers and will rename the method accordingly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed to MemberNameToCamelCase
{ | ||
// Basic cases where only the first char needs to be modified | ||
chars[0] = char.ToLowerInvariant(chars[0]); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there much reason to have this special case? It looks to me like this would immediately hit the 'break' condition in the loop.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, I see it's not clear from the comment but this branch is functionally required. Without it, the logic would never look at the value of chars[1]
and would produce an incorrect result for inputs like OnCLICK
(it would produce onclick
instead of onCLICK
).
Basically chars[0]
and chars[1]
are both special, because the "when to stop" logic is based on looking at the n+2
character versus the one we're currently lowercasing. Since the loop starts at index 0 that means it only starts looking at the case of characters from 2 onwards.
I'll update the comment to clarify this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left some minor comments here but overall this seems sound to me.
…retain case on dictionary keys)
d247ed4
to
bfce965
Compare
* Add camelCase utility * Use camelCase when JSON-serializing (but not for dictionary keys) * Make JSON deserialization treat member names case-insensitively (but retain case on dictionary keys) * Use camelCase in JSON in the samples and templates * Reverse the order of the params for the camelcase test because it's weird otherwise * CR feedback
We know from feedback that C# developers pretty much universally want automatic PascalCase-camelCase conversions enabled during JSON serialization/deserialization. So with this PR,
JsonUtility
will now:Since
JsonUtility
is used internally forHttpClient
'sXyzJsonAsync
methods (e.g.,GetJsonAsync
), it affects what data is sent, and broadens what incoming data is accepted. Likewise, sinceJsonUtility
is used forRegisteredFunction.Invoke
, it affects how complex .NET objects are passed to JS-side code.A very important design point is that this is not overridable or configurable. We are trying very hard not to develop a whole new sophisticated JSON library inside Blazor. Our goal for the built-in JSON utility is to support the most basic and common things that are absolutely essential for core scenarios. Many developers will want something more customisable, which is fine: there are lots of other JSON libraries on NuGet (and where necessary, we'll adapt our APIs to make sure you can use them). JSON libraries should be separate, independent projects from Blazor.
Hopefully this change will satisfy the majority of developers.
Breaking change If you do sophisticated JS interop and have JS-side code that relies on property names arriving in PascalCase, you'll need to change it to expect camelCase.