@@ -13,11 +13,21 @@ namespace System
1313{
1414 public partial class Uri
1515 {
16- //
17- // All public ctors go through here
18- //
16+ /// <summary>Helper called by all constructors to construct the Uri.</summary>
1917 [ MemberNotNull ( nameof ( _string ) ) ]
2018 private void CreateThis ( string ? uri , bool dontEscape , UriKind uriKind , in UriCreationOptions creationOptions = default )
19+ {
20+ UriFormatException ? e = TryCreateThis ( uri , dontEscape , uriKind , in creationOptions ) ;
21+
22+ if ( e is not null )
23+ {
24+ throw e ;
25+ }
26+ }
27+
28+ /// <summary>Core helper called by all constructors and TryCreate factories to construct the Uri.</summary>
29+ [ MemberNotNull ( nameof ( _string ) ) ]
30+ private UriFormatException ? TryCreateThis ( string ? uri , bool dontEscape , UriKind uriKind , in UriCreationOptions creationOptions = default )
2131 {
2232 DebugAssertInCtor ( ) ;
2333
@@ -37,15 +47,6 @@ private void CreateThis(string? uri, bool dontEscape, UriKind uriKind, in UriCre
3747 _flags |= Flags . DisablePathAndQueryCanonicalization ;
3848
3949 ParsingError err = ParseScheme ( _string , ref _flags , ref _syntax ! ) ;
40-
41- UriFormatException ? e = InitializeUri ( err , uriKind ) ;
42- if ( e != null )
43- throw e ;
44- }
45-
46- private UriFormatException ? InitializeUri ( ParsingError err , UriKind uriKind )
47- {
48- DebugAssertInCtor ( ) ;
4950 Debug . Assert ( ( err is ParsingError . None ) == ( _syntax is not null ) ) ;
5051
5152 bool hasUnicode = false ;
@@ -63,19 +64,10 @@ private void CreateThis(string? uri, bool dontEscape, UriKind uriKind, in UriCre
6364 // and we'll allow relative Uri's, then create one.
6465 if ( uriKind != UriKind . Absolute && err <= ParsingError . LastErrorOkayForRelativeUris )
6566 {
66- _flags &= Flags . UserEscaped | Flags . HasUnicode ; // the only flags that makes sense for a relative uri
67- if ( hasUnicode )
68- {
69- // Iri'ze and then normalize relative uris
70- var vsb = new ValueStringBuilder ( stackalloc char [ StackallocThreshold ] ) ;
71- IriHelper . EscapeUnescapeIri ( ref vsb , _originalUnicodeString , isQuery : false ) ;
72- _string = vsb . ToString ( ) ;
73- }
74- return null ;
67+ goto SwitchToRelativeUri ;
7568 }
7669
7770 // This is a fatal error based solely on scheme name parsing
78- _string = null ! ; // make it be invalid Uri
7971 return GetException ( err ) ;
8072 }
8173
@@ -85,9 +77,7 @@ private void CreateThis(string? uri, bool dontEscape, UriKind uriKind, in UriCre
8577 {
8678 if ( uriKind == UriKind . Relative )
8779 {
88- _syntax = null ! ; // make it be relative Uri
89- _flags &= Flags . UserEscaped ; // the only flag that makes sense for a relative uri
90- return null ;
80+ goto SwitchToRelativeUri ;
9181 }
9282
9383 // V1 compat
@@ -98,9 +88,7 @@ private void CreateThis(string? uri, bool dontEscape, UriKind uriKind, in UriCre
9888 ( ( _string . Length >= 2 && ( _string [ 0 ] != '\\ ' || _string [ 1 ] != '\\ ' ) )
9989 || ( ! OperatingSystem . IsWindows ( ) && InFact ( Flags . UnixPath ) ) ) )
10090 {
101- _syntax = null ! ; //make it be relative Uri
102- _flags &= Flags . UserEscaped ; // the only flag that makes sense for a relative uri
103- return null ;
91+ goto SwitchToRelativeUri ;
10492 // Otherwise an absolute file Uri wins when it's of the form "\\something"
10593 }
10694 }
@@ -112,9 +100,7 @@ private void CreateThis(string? uri, bool dontEscape, UriKind uriKind, in UriCre
112100 if ( uriKind != UriKind . Absolute && err <= ParsingError . LastErrorOkayForRelativeUris )
113101 {
114102 // RFC 3986 Section 5.4.2 - http:(relativeUri) may be considered a valid relative Uri.
115- _syntax = null ! ; // convert to relative uri
116- _flags &= Flags . UserEscaped ; // the only flag that makes sense for a relative uri
117- return null ;
103+ goto SwitchToRelativeUri ;
118104 }
119105
120106 return GetException ( err ) ;
@@ -164,6 +150,23 @@ private void CreateThis(string? uri, bool dontEscape, UriKind uriKind, in UriCre
164150 }
165151
166152 // We have a valid absolute Uri.
153+ DebugSetLeftCtor ( ) ;
154+ return null ;
155+
156+ SwitchToRelativeUri :
157+ Debug . Assert ( uriKind != UriKind . Absolute ) ;
158+
159+ _syntax = null ! ;
160+ _flags &= Flags . UserEscaped | Flags . HasUnicode ; // the only flags that make sense for a relative uri
161+
162+ if ( hasUnicode )
163+ {
164+ var vsb = new ValueStringBuilder ( stackalloc char [ StackallocThreshold ] ) ;
165+ IriHelper . EscapeUnescapeIri ( ref vsb , _originalUnicodeString , isQuery : false ) ;
166+ _string = vsb . ToString ( ) ;
167+ }
168+
169+ DebugSetLeftCtor ( ) ;
167170 return null ;
168171 }
169172
@@ -220,7 +223,6 @@ private static bool CheckForUnicodeOrEscapedUnreserved(string data)
220223 public static bool TryCreate ( [ NotNullWhen ( true ) , StringSyntax ( StringSyntaxAttribute . Uri , "uriKind" ) ] string ? uriString , UriKind uriKind , [ NotNullWhen ( true ) ] out Uri ? result )
221224 {
222225 result = CreateHelper ( uriString , false , uriKind ) ;
223- result ? . DebugSetLeftCtor ( ) ;
224226 return result is not null ;
225227 }
226228
@@ -234,7 +236,6 @@ public static bool TryCreate([NotNullWhen(true), StringSyntax(StringSyntaxAttrib
234236 public static bool TryCreate ( [ NotNullWhen ( true ) , StringSyntax ( StringSyntaxAttribute . Uri ) ] string ? uriString , in UriCreationOptions creationOptions , [ NotNullWhen ( true ) ] out Uri ? result )
235237 {
236238 result = CreateHelper ( uriString , false , UriKind . Absolute , in creationOptions ) ;
237- result ? . DebugSetLeftCtor ( ) ;
238239 return result is not null ;
239240 }
240241
@@ -283,7 +284,6 @@ public static bool TryCreate(Uri? baseUri, Uri? relativeUri, [NotNullWhen(true)]
283284 result ??= CreateHelper ( newUriString ! , dontEscape , UriKind . Absolute ) ;
284285 Debug . Assert ( result is null || result . IsAbsoluteUri ) ;
285286
286- result ? . DebugSetLeftCtor ( ) ;
287287 return result is not null ;
288288 }
289289
@@ -625,77 +625,28 @@ public static string EscapeDataString(ReadOnlySpan<char> charsToEscape) =>
625625 public static bool TryEscapeDataString ( ReadOnlySpan < char > charsToEscape , Span < char > destination , out int charsWritten ) =>
626626 UriHelper . TryEscapeDataString ( charsToEscape , destination , out charsWritten ) ;
627627
628- // Should never be used except by the below method
629- private Uri ( Flags flags , UriParser ? uriParser , string uri )
630- {
631- _flags = flags ;
632- _syntax = uriParser ! ;
633- _string = uri ;
634-
635- if ( uriParser is null )
636- {
637- // Relative Uris are fully initialized after the call to this constructor
638- // Absolute Uris will be initialized with a call to InitializeUri on the newly created instance
639- DebugSetLeftCtor ( ) ;
640- }
641- }
628+ #pragma warning disable CS8618 // _string will be initialized by TryCreateThis later.
629+ /// <summary>Must never be used except by <see cref="CreateHelper(string?, bool, UriKind, in UriCreationOptions)"/>.</summary>
630+ private Uri ( ) { }
631+ #pragma warning restore CS8618
642632
643- //
644- // a Uri.TryCreate() method goes through here.
645- //
633+ /// <summary>Called by TryCreate.</summary>
646634 internal static Uri ? CreateHelper ( string ? uriString , bool dontEscape , UriKind uriKind , in UriCreationOptions creationOptions = default )
647635 {
648636 if ( uriString is null )
649637 {
650638 return null ;
651639 }
652640
653- if ( uriKind is < UriKind . RelativeOrAbsolute or > UriKind . Relative )
654- {
655- throw new ArgumentException ( SR . Format ( SR . net_uri_InvalidUriKind , uriKind ) ) ;
656- }
657-
658- UriParser ? syntax = null ;
659- Flags flags = Flags . Zero ;
660- ParsingError err = ParseScheme ( uriString , ref flags , ref syntax ) ;
661-
662- if ( dontEscape )
663- flags |= Flags . UserEscaped ;
664-
665- if ( creationOptions . DangerousDisablePathAndQueryCanonicalization )
666- flags |= Flags . DisablePathAndQueryCanonicalization ;
667-
668- // We won't use User factory for these errors
669- if ( err != ParsingError . None )
670- {
671- // If it looks as a relative Uri, custom factory is ignored
672- if ( uriKind != UriKind . Absolute && err <= ParsingError . LastErrorOkayForRelativeUris )
673- return new Uri ( ( flags & Flags . UserEscaped ) , null , uriString ) ;
674-
675- return null ;
676- }
677-
678- // Cannot be relative Uri if came here
679- Debug . Assert ( syntax != null ) ;
680- Uri result = new Uri ( flags , syntax , uriString ) ;
681-
682- // Validate instance using ether built in or a user Parser
641+ Uri result = new ( ) ;
683642 try
684643 {
685- UriFormatException ? e = result . InitializeUri ( err , uriKind ) ;
686-
687- if ( e == null )
688- {
689- result . DebugSetLeftCtor ( ) ;
690- return result ;
691- }
692-
693- return null ;
644+ UriFormatException ? e = result . TryCreateThis ( uriString , dontEscape , uriKind , in creationOptions ) ;
645+ return e is null ? result : null ;
694646 }
695647 catch ( UriFormatException )
696648 {
697- Debug . Assert ( ! syntax . IsSimple , "A UriPraser threw on InitializeAndValidate." ) ;
698- // A precaution since custom Parser should never throw in this case.
649+ Debug . Assert ( result . Syntax is { IsSimple : false } , "A custom UriParser threw on InitializeAndValidate." ) ;
699650 return null ;
700651 }
701652 }
@@ -938,6 +889,7 @@ internal bool IsBaseOfHelper(Uri uriLink)
938889 private void CreateThisFromUri ( Uri otherUri )
939890 {
940891 DebugAssertInCtor ( ) ;
892+ Debug . Assert ( ( otherUri . _flags & Flags . Debug_LeftConstructor ) != 0 ) ;
941893
942894 _flags = otherUri . _flags ;
943895
0 commit comments