This repository was archived by the owner on Jan 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Port System.Net.WebUtility missing members #13875
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
src/System.Runtime.Extensions/tests/System/Net/WebUtility.netstandard1.7.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
| // See the LICENSE file in the project root for more information. | ||
|
|
||
| using System.Globalization; | ||
| using System.IO; | ||
| using Xunit; | ||
|
|
||
| namespace System.Net.Tests | ||
| { | ||
| public partial class WebUtilityTests | ||
| { | ||
| [Theory] | ||
| [MemberData(nameof(HtmlDecode_TestData))] | ||
| public static void HtmlDecode_TextWriterOutput(string value, string expected) | ||
| { | ||
| if(value == null) | ||
| expected = string.Empty; | ||
| StringWriter output = new StringWriter(CultureInfo.InvariantCulture); | ||
| WebUtility.HtmlDecode(value, output); | ||
| Assert.Equal(expected, output.ToString()); | ||
| } | ||
|
|
||
| [Theory] | ||
| [MemberData(nameof(HtmlEncode_TestData))] | ||
| public static void HtmlEncode_TextWriterOutput(string value, string expected) | ||
| { | ||
| if(value == null) | ||
| expected = string.Empty; | ||
| StringWriter output = new StringWriter(CultureInfo.InvariantCulture); | ||
| WebUtility.HtmlEncode(value, output); | ||
| Assert.Equal(expected, output.ToString()); | ||
| } | ||
| } | ||
| } |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 is sufficient to bring the functionality to .NET Core, but it can be improved... In desktop, the encoded chars are written directly to the
TextWriter, whereas with this, a (potentially large) string is being allocated and then that string is written to theTextWriter. It'd be nice to avoid the string allocation.In desktop, the shared implementation is in
HtmlEncode(string, TextWriter)andHtmlEncode(string)allocates aStringWriterto pass toHtmlEncode(string, TextWriter). However, in .NET Core, since the other overload wasn't present,HtmlEncode(string)was changed to useStringBuilder(acquired from aStringBuilderCache) instead of usingStringWriter.This could be reworked to share an implementation, without having to switch back to the desktop implementation.
Something like...
Of course, this could be done subsequently in a separate PR.
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 approach works. @safern and I discussed this before the PR went up.
The downside seems to be that it would make the existing code slower and would introduce a couple of allocations for the 2 lambdas.
Uh oh!
There was an error while loading. Please reload this page.
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.
The compiler will lazily allocate and cache/reuse the lambda delegate instances.
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 would be better than the approach we discussed earlier, right? @AlexGhiondea
Just to give you a little bit of context @justinvp, we were thinking of creating an internal abstract class
WriterBaseClass(this is just a random name), and making two other internal classes that would inherit from this one, those to classes would be:SBWrapperandTextWriterWrapperwhere them would override virtualwrite(char)andwrite(string)methods fromWriterBaseClassthat would write either to theStringBuilderor theTextWriter.SBWrapperwould overrideToStringand callStringBuilderCache.GetStringAndRelease(sb).But I think your approach works better cause this one would have extra allocations as well and would have to make virtual calls.
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.
By the way, I noticed the same problem being solved using delegates in a recent PR:
corefx/src/System.Runtime.Extensions/src/System/Security/SecurityElement.cs
Lines 546 to 560 in 768e18c
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.
@safern I think they are just as good. Splitting into base classes makes it easier if you have more than 2 methods you would need to wrap. Otherwise you end up with a lot of lambdas you need to write :).
There should not be a lot of performance difference between calling via a delegate and calling via callvirt.
And if we don't think the original code is used on the hot path, then this becomes a question of what is the nicest way to write the code and @justinvp came up with an elegant one.
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 I see! Thanks for explaining :) @AlexGhiondea
Then I'll go for @justinvp solution!
Will update this PR.
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.
@justinvp Your solution seems like it would be slower for the main path, since an extra function call would be added for every char/string appended. Since it's more common to call the overload that returns a string rather than one that writes it to a
TextWriter, it seems like what's currently checked in is the best solution.