44using System ;
55using System . Collections ;
66using System . Collections . Generic ;
7+ using System . Runtime . CompilerServices ;
78using Microsoft . Extensions . Internal ;
89
910namespace Microsoft . Extensions . Primitives
@@ -16,19 +17,16 @@ public struct StringValues : IList<string>, IReadOnlyList<string>, IEquatable<St
1617 private static readonly string [ ] EmptyArray = new string [ 0 ] ;
1718 public static readonly StringValues Empty = new StringValues ( EmptyArray ) ;
1819
19- private readonly string _value ;
20- private readonly string [ ] _values ;
20+ private readonly object _value ;
2121
2222 public StringValues ( string value )
2323 {
2424 _value = value ;
25- _values = null ;
2625 }
2726
2827 public StringValues ( string [ ] values )
2928 {
30- _value = null ;
31- _values = values ;
29+ _value = values ;
3230 }
3331
3432 public static implicit operator StringValues ( string value )
@@ -51,8 +49,11 @@ public static implicit operator string[] (StringValues value)
5149 return value . GetArrayValue ( ) ;
5250 }
5351
54- public int Count => _value != null ? 1 : ( _values ? . Length ?? 0 ) ;
52+ public int Count => ( _value is string ) ? 1 : GetArrayCount ( ) ;
5553
54+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
55+ private int GetArrayCount ( ) => ( ( _value as string [ ] ) ? . Length ?? 0 ) ;
56+
5657 bool ICollection < string > . IsReadOnly
5758 {
5859 get { return true ; }
@@ -68,49 +69,88 @@ public string this[int index]
6869 {
6970 get
7071 {
71- if ( _values != null )
72- {
73- return _values [ index ] ; // may throw
74- }
75- if ( index == 0 && _value != null )
72+ if ( index == 0 )
7673 {
77- return _value ;
74+ var stringVal = _value as string ;
75+ if ( stringVal != null )
76+ {
77+ return stringVal ;
78+ }
7879 }
79- return EmptyArray [ 0 ] ; // throws
80+
81+ return GetArrayItem ( index ) ;
8082 }
8183 }
8284
85+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
86+ private string GetArrayItem ( int index )
87+ {
88+ var arrayValue = _value as string [ ] ;
89+ if ( arrayValue != null )
90+ {
91+ return arrayValue [ index ] ; // may throw
92+ }
93+
94+ return EmptyArray [ 0 ] ; // throws
95+ }
96+
8397 public override string ToString ( )
8498 {
8599 return GetStringValue ( ) ?? string . Empty ;
86100 }
87101
88102 private string GetStringValue ( )
89103 {
90- if ( _values == null )
104+ var stringVal = _value as string ;
105+ if ( stringVal != null )
91106 {
92- return _value ;
107+ return stringVal ;
93108 }
94- switch ( _values . Length )
109+
110+ return GetArrayStringValue ( ) ;
111+ }
112+
113+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
114+ private string GetArrayStringValue ( )
115+ {
116+ var arrayValue = _value as string [ ] ;
117+ if ( arrayValue != null )
95118 {
96- case 0 : return null ;
97- case 1 : return _values [ 0 ] ;
98- default : return string . Join ( "," , _values ) ;
119+ switch ( arrayValue . Length )
120+ {
121+ case 0 : return null ;
122+ case 1 : return arrayValue [ 0 ] ;
123+ default : return string . Join ( "," , arrayValue ) ;
124+ }
99125 }
126+ return null ;
100127 }
101-
128+
102129 public string [ ] ToArray ( )
103130 {
104131 return GetArrayValue ( ) ?? EmptyArray ;
105132 }
106133
107134 private string [ ] GetArrayValue ( )
108135 {
109- if ( _value != null )
136+ var arrayValue = _value as string [ ] ;
137+ if ( arrayValue != null )
110138 {
111- return new [ ] { _value } ;
139+ return arrayValue ;
112140 }
113- return _values ;
141+
142+ return GetStringArrayValue ( ) ;
143+ }
144+
145+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
146+ private string [ ] GetStringArrayValue ( )
147+ {
148+ var stringVal = _value as string ;
149+ if ( stringVal != null )
150+ {
151+ return new [ ] { stringVal } ;
152+ }
153+ return null ;
114154 }
115155
116156 int IList < string > . IndexOf ( string item )
@@ -120,22 +160,29 @@ int IList<string>.IndexOf(string item)
120160
121161 private int IndexOf ( string item )
122162 {
123- if ( _values != null )
163+ var arrayValue = _value as string [ ] ;
164+ if ( arrayValue != null )
124165 {
125- var values = _values ;
126- for ( int i = 0 ; i < values . Length ; i ++ )
166+ for ( int i = 0 ; i < arrayValue . Length ; i ++ )
127167 {
128- if ( string . Equals ( values [ i ] , item , StringComparison . Ordinal ) )
168+ if ( string . Equals ( arrayValue [ i ] , item , StringComparison . Ordinal ) )
129169 {
130170 return i ;
131171 }
132172 }
133173 return - 1 ;
134174 }
135175
136- if ( _value != null )
176+ return IndexOfString ( item ) ;
177+ }
178+
179+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
180+ private int IndexOfString ( string item )
181+ {
182+ var stringVal = _value as string ;
183+ if ( stringVal != null )
137184 {
138- return string . Equals ( _value , item , StringComparison . Ordinal ) ? 0 : - 1 ;
185+ return string . Equals ( stringVal , item , StringComparison . Ordinal ) ? 0 : - 1 ;
139186 }
140187
141188 return - 1 ;
@@ -153,13 +200,15 @@ void ICollection<string>.CopyTo(string[] array, int arrayIndex)
153200
154201 private void CopyTo ( string [ ] array , int arrayIndex )
155202 {
156- if ( _values != null )
203+ var arrayValue = _value as string [ ] ;
204+ if ( arrayValue != null )
157205 {
158- Array . Copy ( _values , 0 , array , arrayIndex , _values . Length ) ;
206+ Array . Copy ( arrayValue , 0 , array , arrayIndex , arrayValue . Length ) ;
159207 return ;
160208 }
161209
162- if ( _value != null )
210+ var stringVal = _value as string ;
211+ if ( stringVal != null )
163212 {
164213 if ( array == null )
165214 {
@@ -175,7 +224,7 @@ private void CopyTo(string[] array, int arrayIndex)
175224 $ "'{ nameof ( array ) } ' is not long enough to copy all the items in the collection. Check '{ nameof ( arrayIndex ) } ' and '{ nameof ( array ) } ' length.") ;
176225 }
177226
178- array [ arrayIndex ] = _value ;
227+ array [ arrayIndex ] = stringVal ;
179228 }
180229 }
181230
@@ -221,18 +270,27 @@ IEnumerator IEnumerable.GetEnumerator()
221270
222271 public static bool IsNullOrEmpty ( StringValues value )
223272 {
224- if ( value . _values == null )
273+ var stringVal = value . _value as string ;
274+ if ( stringVal != null )
225275 {
226- return string . IsNullOrEmpty ( value . _value ) ;
276+ return string . IsNullOrEmpty ( stringVal ) ;
227277 }
228- switch ( value . _values . Length )
278+
279+ return value . IsNullOrEmptyArray ( ) ;
280+ }
281+
282+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
283+ private bool IsNullOrEmptyArray ( )
284+ {
285+ var arrayValue = _value as string [ ] ;
286+ switch ( arrayValue . Length )
229287 {
230288 case 0 : return true ;
231- case 1 : return string . IsNullOrEmpty ( value . _values [ 0 ] ) ;
289+ case 1 : return string . IsNullOrEmpty ( arrayValue [ 0 ] ) ;
232290 default : return false ;
233291 }
234292 }
235-
293+
236294 public static StringValues Concat ( StringValues values1 , StringValues values2 )
237295 {
238296 var count1 = values1 . Count ;
@@ -405,17 +463,24 @@ public override bool Equals(object obj)
405463
406464 public override int GetHashCode ( )
407465 {
408- if ( _values == null )
466+ var stringVal = _value as string ;
467+ if ( stringVal != null )
409468 {
410- return _value == null ? 0 : _value . GetHashCode ( ) ;
469+ return stringVal . GetHashCode ( ) ;
411470 }
412471
413- var hcc = new HashCodeCombiner ( ) ;
414- for ( var i = 0 ; i < _values . Length ; i ++ )
472+ var arrayValue = _value as string [ ] ;
473+ if ( arrayValue != null )
415474 {
416- hcc . Add ( _values [ i ] ) ;
475+ var hcc = new HashCodeCombiner ( ) ;
476+ for ( var i = 0 ; i < arrayValue . Length ; i ++ )
477+ {
478+ hcc . Add ( arrayValue [ i ] ) ;
479+ }
480+ return hcc . CombinedHash ;
417481 }
418- return hcc . CombinedHash ;
482+
483+ return 0 ;
419484 }
420485
421486 public struct Enumerator : IEnumerator < string >
@@ -426,8 +491,8 @@ public struct Enumerator : IEnumerator<string>
426491
427492 public Enumerator ( ref StringValues values )
428493 {
429- _values = values . _values ;
430- _current = values . _value ;
494+ _current = values . _value as string ;
495+ _values = values . _value as string [ ] ;
431496 _index = 0 ;
432497 }
433498
0 commit comments