@@ -229,7 +229,7 @@ private static string InsertDimensionSize(string value, int dimensionSize)
229
229
return value + ": " + dimensionSize ;
230
230
}
231
231
232
- private VariableDetails [ ] GetChildren ( object obj , ILogger logger )
232
+ private static VariableDetails [ ] GetChildren ( object obj , ILogger logger )
233
233
{
234
234
List < VariableDetails > childVariables = new ( ) ;
235
235
@@ -238,86 +238,82 @@ private VariableDetails[] GetChildren(object obj, ILogger logger)
238
238
return childVariables . ToArray ( ) ;
239
239
}
240
240
241
- try
242
- {
243
- PSObject psObject = obj as PSObject ;
241
+ // NOTE: Variable expansion now takes place on the pipeline thread as an async delegate,
242
+ // so expansion of children that cause PowerShell script code to execute should
243
+ // generally work. However, we might need more error handling.
244
+ PSObject psObject = obj as PSObject ;
244
245
245
- if ( ( psObject != null ) &&
246
- ( psObject . TypeNames [ 0 ] == typeof ( PSCustomObject ) . ToString ( ) ) )
246
+ if ( ( psObject != null ) &&
247
+ ( psObject . TypeNames [ 0 ] == typeof ( PSCustomObject ) . ToString ( ) ) )
248
+ {
249
+ // PowerShell PSCustomObject's properties are completely defined by the ETS type system.
250
+ logger . LogDebug ( "PSObject was a PSCustomObject" ) ;
251
+ childVariables . AddRange (
252
+ psObject
253
+ . Properties
254
+ . Select ( p => new VariableDetails ( p ) ) ) ;
255
+ }
256
+ else
257
+ {
258
+ // If a PSObject other than a PSCustomObject, unwrap it.
259
+ if ( psObject != null )
247
260
{
248
- // PowerShell PSCustomObject's properties are completely defined by the ETS type system.
261
+ // First add the PSObject's ETS properties
262
+ logger . LogDebug ( "PSObject was something else, first getting ETS properties" ) ;
249
263
childVariables . AddRange (
250
264
psObject
251
265
. Properties
266
+ // Here we check the object's MemberType against the `Properties`
267
+ // bit-mask to determine if this is a property. Hence the selection
268
+ // will only include properties.
269
+ . Where ( p => ( PSMemberTypes . Properties & p . MemberType ) is not 0 )
252
270
. Select ( p => new VariableDetails ( p ) ) ) ;
271
+
272
+ obj = psObject . BaseObject ;
253
273
}
254
- else
274
+
275
+ // We're in the realm of regular, unwrapped .NET objects
276
+ if ( obj is IDictionary dictionary )
255
277
{
256
- // If a PSObject other than a PSCustomObject, unwrap it.
257
- if ( psObject != null )
278
+ logger . LogDebug ( "PSObject was an IDictionary" ) ;
279
+ // Buckle up kids, this is a bit weird. We could not use the LINQ
280
+ // operator OfType<DictionaryEntry>. Even though R# will squiggle the
281
+ // "foreach" keyword below and offer to convert to a LINQ-expression - DON'T DO IT!
282
+ // The reason is that LINQ extension methods work with objects of type
283
+ // IEnumerable. Objects of type Dictionary<,>, respond to iteration via
284
+ // IEnumerable by returning KeyValuePair<,> objects. Unfortunately non-generic
285
+ // dictionaries like HashTable return DictionaryEntry objects.
286
+ // It turns out that iteration via C#'s foreach loop, operates on the variable's
287
+ // type which in this case is IDictionary. IDictionary was designed to always
288
+ // return DictionaryEntry objects upon iteration and the Dictionary<,> implementation
289
+ // honors that when the object is reinterpreted as an IDictionary object.
290
+ // FYI, a test case for this is to open $PSBoundParameters when debugging a
291
+ // function that defines parameters and has been passed parameters.
292
+ // If you open the $PSBoundParameters variable node in this scenario and see nothing,
293
+ // this code is broken.
294
+ foreach ( DictionaryEntry entry in dictionary )
258
295
{
259
- // First add the PSObject's ETS properties
260
- childVariables . AddRange (
261
- psObject
262
- . Properties
263
- // Here we check the object's MemberType against the `Properties`
264
- // bit-mask to determine if this is a property. Hence the selection
265
- // will only include properties.
266
- . Where ( p => ( PSMemberTypes . Properties & p . MemberType ) is not 0 )
267
- . Select ( p => new VariableDetails ( p ) ) ) ;
268
-
269
- obj = psObject . BaseObject ;
296
+ childVariables . Add (
297
+ new VariableDetails (
298
+ "[" + entry . Key + "]" ,
299
+ entry ) ) ;
270
300
}
271
-
272
- // We're in the realm of regular, unwrapped .NET objects
273
- if ( obj is IDictionary dictionary )
274
- {
275
- // Buckle up kids, this is a bit weird. We could not use the LINQ
276
- // operator OfType<DictionaryEntry>. Even though R# will squiggle the
277
- // "foreach" keyword below and offer to convert to a LINQ-expression - DON'T DO IT!
278
- // The reason is that LINQ extension methods work with objects of type
279
- // IEnumerable. Objects of type Dictionary<,>, respond to iteration via
280
- // IEnumerable by returning KeyValuePair<,> objects. Unfortunately non-generic
281
- // dictionaries like HashTable return DictionaryEntry objects.
282
- // It turns out that iteration via C#'s foreach loop, operates on the variable's
283
- // type which in this case is IDictionary. IDictionary was designed to always
284
- // return DictionaryEntry objects upon iteration and the Dictionary<,> implementation
285
- // honors that when the object is reinterpreted as an IDictionary object.
286
- // FYI, a test case for this is to open $PSBoundParameters when debugging a
287
- // function that defines parameters and has been passed parameters.
288
- // If you open the $PSBoundParameters variable node in this scenario and see nothing,
289
- // this code is broken.
290
- foreach ( DictionaryEntry entry in dictionary )
291
- {
292
- childVariables . Add (
293
- new VariableDetails (
294
- "[" + entry . Key + "]" ,
295
- entry ) ) ;
296
- }
297
- }
298
- else if ( obj is IEnumerable enumerable and not string )
301
+ }
302
+ else if ( obj is IEnumerable enumerable and not string )
303
+ {
304
+ logger . LogDebug ( "PSObject was an IEnumerable" ) ;
305
+ int i = 0 ;
306
+ foreach ( object item in enumerable )
299
307
{
300
- int i = 0 ;
301
- foreach ( object item in enumerable )
302
- {
303
- childVariables . Add (
304
- new VariableDetails (
305
- "[" + i ++ + "]" ,
306
- item ) ) ;
307
- }
308
+ childVariables . Add (
309
+ new VariableDetails (
310
+ "[" + i ++ + "]" ,
311
+ item ) ) ;
308
312
}
309
-
310
- AddDotNetProperties ( obj , childVariables ) ;
311
313
}
312
- }
313
- catch ( GetValueInvocationException ex )
314
- {
315
- // This exception occurs when accessing the value of a
316
- // variable causes a script to be executed. Right now
317
- // we aren't loading children on the pipeline thread so
318
- // this causes an exception to be raised. In this case,
319
- // just return an empty list of children.
320
- logger . LogWarning ( $ "Failed to get properties of variable { Name } , value invocation was attempted: { ex . Message } ") ;
314
+
315
+ logger . LogDebug ( "Adding .NET properties to PSObject" ) ;
316
+ AddDotNetProperties ( obj , childVariables ) ;
321
317
}
322
318
323
319
return childVariables . ToArray ( ) ;
0 commit comments