2018-02-13 09:23:53 -08:00
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
2016-07-29 13:02:49 -07:00
2016-03-30 14:20:52 -07:00
using System ;
using System.Collections ;
using System.Collections.Concurrent ;
using System.Collections.Generic ;
using System.Collections.ObjectModel ;
2019-04-30 10:25:11 +05:00
using System.ComponentModel ;
2017-04-17 11:52:38 -07:00
using System.Data ;
2019-04-30 10:25:11 +05:00
using System.Diagnostics.CodeAnalysis ;
2016-03-30 14:20:52 -07:00
using System.Dynamic ;
2019-04-30 10:25:11 +05:00
using System.Globalization ;
2016-03-30 14:20:52 -07:00
using System.Linq ;
using System.Linq.Expressions ;
using System.Management.Automation ;
using System.Management.Automation.Internal ;
2019-04-30 10:25:11 +05:00
using System.Management.Automation.Language ;
2016-03-30 14:20:52 -07:00
using System.Management.Automation.Runspaces ;
2019-04-30 10:25:11 +05:00
using System.Reflection ;
using System.Runtime.CompilerServices ;
2016-03-30 14:20:52 -07:00
using System.Runtime.Serialization ;
2019-04-30 10:25:11 +05:00
using System.Text ;
using System.Xml ;
2016-03-30 14:20:52 -07:00
using Microsoft.Management.Infrastructure ;
2018-06-21 09:57:14 -07:00
#if ! UNIX
2016-03-30 14:20:52 -07:00
using System.DirectoryServices ;
2018-06-21 09:57:14 -07:00
using System.Management ;
2016-03-30 14:20:52 -07:00
#endif
#pragma warning disable 1634 , 1691 // Stops compiler from warning about unknown warnings
#pragma warning disable 56500
namespace System.Management.Automation
{
/// <summary>
2017-01-16 13:31:14 -08:00
/// Wraps an object providing alternate views of the available members
/// and ways to extend them. Members can be methods, properties,
2016-03-30 14:20:52 -07:00
/// parameterized properties, etc.
/// </summary>
/// <remarks>
/// It is permitted to subclass <see cref="PSObject"/>
/// but there is no established scenario for doing this, nor has it been tested.
/// </remarks>
[TypeDescriptionProvider(typeof(PSObjectTypeDescriptionProvider))]
[Serializable]
2016-07-29 13:02:49 -07:00
public class PSObject : IFormattable , IComparable , ISerializable , IDynamicMetaObjectProvider
2016-03-30 14:20:52 -07:00
{
#region constructors
#region private to the constructors
internal TypeTable GetTypeTable ()
{
2018-09-25 21:27:43 -07:00
if ( _typeTable != null && _typeTable . TryGetTarget ( out TypeTable typeTable ))
2016-03-30 14:20:52 -07:00
{
return typeTable ;
}
ExecutionContext context = LocalPipeline . GetExecutionContextFromTLS ();
2018-09-25 21:27:43 -07:00
return context ?. TypeTable ;
2016-03-30 14:20:52 -07:00
}
internal static T TypeTableGetMemberDelegate < T >( PSObject msjObj , string name ) where T : PSMemberInfo
{
TypeTable table = msjObj . GetTypeTable ();
return TypeTableGetMemberDelegate < T >( msjObj , table , name );
}
private static T TypeTableGetMemberDelegate < T >( PSObject msjObj , TypeTable typeTableToUse , string name ) where T : PSMemberInfo
{
if ( typeTableToUse == null )
{
return null ;
}
PSMemberInfoInternalCollection < PSMemberInfo > allMembers = typeTableToUse . GetMembers < PSMemberInfo >( msjObj . InternalTypeNames );
PSMemberInfo member = allMembers [ name ];
if ( member == null )
{
2019-03-21 02:43:52 +01:00
PSObject . MemberResolution . WriteLine ( "\"{0}\" NOT present in type table." , name );
2016-03-30 14:20:52 -07:00
return null ;
}
2018-09-25 21:27:43 -07:00
if ( member is T memberAsT )
2016-03-30 14:20:52 -07:00
{
2019-03-21 02:43:52 +01:00
PSObject . MemberResolution . WriteLine ( "\"{0}\" present in type table." , name );
2016-03-30 14:20:52 -07:00
return memberAsT ;
}
2018-12-23 22:20:06 -08:00
2019-03-21 02:43:52 +01:00
PSObject . MemberResolution . WriteLine ( "\"{0}\" from types table ignored because it has type {1} instead of {2}." ,
2016-03-30 14:20:52 -07:00
name , member . GetType (), typeof ( T ));
return null ;
}
internal static PSMemberInfoInternalCollection < T > TypeTableGetMembersDelegate < T >( PSObject msjObj ) where T : PSMemberInfo
{
TypeTable table = msjObj . GetTypeTable ();
return TypeTableGetMembersDelegate < T >( msjObj , table );
}
internal static PSMemberInfoInternalCollection < T > TypeTableGetMembersDelegate < T >( PSObject msjObj , TypeTable typeTableToUse ) where T : PSMemberInfo
{
if ( typeTableToUse == null )
{
return new PSMemberInfoInternalCollection < T >();
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
PSMemberInfoInternalCollection < T > members = typeTableToUse . GetMembers < T >( msjObj . InternalTypeNames );
2019-03-21 02:43:52 +01:00
PSObject . MemberResolution . WriteLine ( "Type table members: {0}." , members . Count );
2016-03-30 14:20:52 -07:00
return members ;
}
2019-03-21 02:43:52 +01:00
internal static T TypeTableGetFirstMemberOrDefaultDelegate < T >( PSObject msjObj , MemberNamePredicate predicate ) where T : PSMemberInfo
{
TypeTable table = msjObj . GetTypeTable ();
return TypeTableGetFirstOrDefaultMemberDelegate < T >( msjObj , table , predicate );
}
internal static T TypeTableGetFirstOrDefaultMemberDelegate < T >( PSObject msjObj , TypeTable typeTableToUse , MemberNamePredicate predicate ) where T : PSMemberInfo
{
return typeTableToUse ?. GetFirstMemberOrDefault < T >( msjObj . InternalTypeNames , predicate );
}
2016-03-30 14:20:52 -07:00
private static T AdapterGetMemberDelegate < T >( PSObject msjObj , string name ) where T : PSMemberInfo
{
2019-03-21 02:43:52 +01:00
if ( msjObj . IsDeserialized )
2016-03-30 14:20:52 -07:00
{
2019-03-21 02:43:52 +01:00
if ( msjObj . AdaptedMembers == null )
2016-03-30 14:20:52 -07:00
{
return null ;
}
2018-12-23 22:20:06 -08:00
2019-03-21 02:43:52 +01:00
T adaptedMember = msjObj . AdaptedMembers [ name ] as T ;
PSObject . MemberResolution . WriteLine ( "Serialized adapted member: {0}." , adaptedMember == null ? "not found" : adaptedMember . Name );
2016-03-30 14:20:52 -07:00
return adaptedMember ;
}
2018-12-23 22:20:06 -08:00
2019-03-21 02:43:52 +01:00
T retValue = msjObj . InternalAdapter . BaseGetMember < T >( msjObj . ImmediateBaseObject , name );
PSObject . MemberResolution . WriteLine ( "Adapted member: {0}." , retValue == null ? "not found" : retValue . Name );
return retValue ;
}
private static T AdapterGetFirstMemberOrDefaultDelegate < T >( PSObject msjObj , MemberNamePredicate predicate ) where T : PSMemberInfo
{
if ( msjObj . IsDeserialized && typeof ( T ). IsAssignableFrom ( typeof ( PSPropertyInfo )))
{
if ( msjObj . AdaptedMembers == null )
{
return null ;
}
foreach ( var adaptedMember in msjObj . AdaptedMembers )
{
if ( predicate ( adaptedMember . Name ))
{
return adaptedMember as T ;
}
}
}
T retValue = msjObj . InternalAdapter . BaseGetFirstMemberOrDefault < T >( msjObj . _immediateBaseObject , predicate );
2016-03-30 14:20:52 -07:00
return retValue ;
}
2016-07-29 13:02:49 -07:00
internal static PSMemberInfoInternalCollection < U > TransformMemberInfoCollection < T , U >( PSMemberInfoCollection < T > source ) where T : PSMemberInfo where U : PSMemberInfo
2016-03-30 14:20:52 -07:00
{
if ( typeof ( T ) == typeof ( U ))
{
// If the types are the same, don't make a copy, return the cached collection.
return source as PSMemberInfoInternalCollection < U >;
}
PSMemberInfoInternalCollection < U > returnValue = new PSMemberInfoInternalCollection < U >();
foreach ( T member in source )
{
2018-09-25 21:27:43 -07:00
if ( member is U tAsU )
2016-03-30 14:20:52 -07:00
{
returnValue . Add ( tAsU );
}
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return returnValue ;
}
private static PSMemberInfoInternalCollection < T > AdapterGetMembersDelegate < T >( PSObject msjObj ) where T : PSMemberInfo
{
2019-03-21 02:43:52 +01:00
if ( msjObj . IsDeserialized )
2016-03-30 14:20:52 -07:00
{
2019-03-21 02:43:52 +01:00
if ( msjObj . AdaptedMembers == null )
2016-03-30 14:20:52 -07:00
{
return new PSMemberInfoInternalCollection < T >();
}
2018-12-23 22:20:06 -08:00
2019-03-21 02:43:52 +01:00
PSObject . MemberResolution . WriteLine ( "Serialized adapted members: {0}." , msjObj . AdaptedMembers . Count );
return TransformMemberInfoCollection < PSPropertyInfo , T >( msjObj . AdaptedMembers );
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
PSMemberInfoInternalCollection < T > retValue = msjObj . InternalAdapter . BaseGetMembers < T >( msjObj . _immediateBaseObject );
2019-03-21 02:43:52 +01:00
PSObject . MemberResolution . WriteLine ( "Adapted members: {0}." , retValue . VisibleCount );
2016-03-30 14:20:52 -07:00
return retValue ;
}
private static PSMemberInfoInternalCollection < T > DotNetGetMembersDelegate < T >( PSObject msjObj ) where T : PSMemberInfo
{
// Don't lookup dotnet members if the object doesn't insist.
2018-06-26 02:37:09 +05:00
if ( msjObj . InternalBaseDotNetAdapter != null )
2016-03-30 14:20:52 -07:00
{
2018-04-04 14:47:44 -07:00
PSMemberInfoInternalCollection < T > retValue = msjObj . InternalBaseDotNetAdapter . BaseGetMembers < T >( msjObj . _immediateBaseObject );
2019-03-21 02:43:52 +01:00
PSObject . MemberResolution . WriteLine ( "DotNet members: {0}." , retValue . VisibleCount );
2016-03-30 14:20:52 -07:00
return retValue ;
}
return new PSMemberInfoInternalCollection < T >();
}
private static T DotNetGetMemberDelegate < T >( PSObject msjObj , string name ) where T : PSMemberInfo
{
// Don't lookup dotnet member if the object doesn't insist.
2018-06-26 02:37:09 +05:00
if ( msjObj . InternalBaseDotNetAdapter != null )
2016-03-30 14:20:52 -07:00
{
2018-04-04 14:47:44 -07:00
T retValue = msjObj . InternalBaseDotNetAdapter . BaseGetMember < T >( msjObj . _immediateBaseObject , name );
2019-03-21 02:43:52 +01:00
PSObject . MemberResolution . WriteLine ( "DotNet member: {0}." , retValue == null ? "not found" : retValue . Name );
2016-03-30 14:20:52 -07:00
return retValue ;
}
return null ;
}
2019-03-21 02:43:52 +01:00
private static T DotNetGetFirstMemberOrDefaultDelegate < T >( PSObject msjObj , MemberNamePredicate predicate ) where T : PSMemberInfo
{
// Don't lookup dotnet member if the object doesn't insist.
return msjObj . InternalBaseDotNetAdapter ?. BaseGetFirstMemberOrDefault < T >( msjObj . _immediateBaseObject , predicate );
}
2016-03-30 14:20:52 -07:00
/// <summary>
2017-01-16 13:31:14 -08:00
/// A collection of delegates to get Extended/Adapted/Dotnet members based on the
2016-03-30 14:20:52 -07:00
/// <paramref name="viewType"/>
/// </summary>
/// <param name="viewType">
/// A filter to select Extended/Adapted/Dotnet view of the object
/// </param>
/// <returns></returns>
internal static Collection < CollectionEntry < PSMemberInfo >> GetMemberCollection ( PSMemberViewTypes viewType )
{
return GetMemberCollection ( viewType , null );
}
/// <summary>
2017-01-16 13:31:14 -08:00
/// A collection of delegates to get Extended/Adapted/Dotnet members based on the
2016-03-30 14:20:52 -07:00
/// <paramref name="viewType"/>
/// </summary>
/// <param name="viewType">
/// A filter to select Extended/Adapted/Dotnet view of the object
/// </param>
/// <param name="backupTypeTable">
/// Backup type table to use if there is no execution context associated with the current thread
/// </param>
/// <returns></returns>
internal static Collection < CollectionEntry < PSMemberInfo >> GetMemberCollection (
PSMemberViewTypes viewType ,
TypeTable backupTypeTable )
{
Collection < CollectionEntry < PSMemberInfo >> returnValue = new Collection < CollectionEntry < PSMemberInfo >>();
if (( viewType & PSMemberViewTypes . Extended ) == PSMemberViewTypes . Extended )
{
if ( backupTypeTable == null )
{
returnValue . Add ( new CollectionEntry < PSMemberInfo >(
PSObject . TypeTableGetMembersDelegate < PSMemberInfo >,
PSObject . TypeTableGetMemberDelegate < PSMemberInfo >,
2019-03-21 02:43:52 +01:00
PSObject . TypeTableGetFirstMemberOrDefaultDelegate < PSMemberInfo >,
2016-03-30 14:20:52 -07:00
true , true , "type table members" ));
}
else
{
returnValue . Add ( new CollectionEntry < PSMemberInfo >(
2018-09-25 21:27:43 -07:00
msjObj => TypeTableGetMembersDelegate < PSMemberInfo >( msjObj , backupTypeTable ),
( msjObj , name ) => TypeTableGetMemberDelegate < PSMemberInfo >( msjObj , backupTypeTable , name ),
2019-03-21 02:43:52 +01:00
( msjObj , predicate ) => TypeTableGetFirstOrDefaultMemberDelegate < PSMemberInfo >( msjObj , backupTypeTable , predicate ),
2016-03-30 14:20:52 -07:00
true , true , "type table members" ));
}
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
if (( viewType & PSMemberViewTypes . Adapted ) == PSMemberViewTypes . Adapted )
{
returnValue . Add ( new CollectionEntry < PSMemberInfo >(
PSObject . AdapterGetMembersDelegate < PSMemberInfo >,
PSObject . AdapterGetMemberDelegate < PSMemberInfo >,
2019-03-21 02:43:52 +01:00
PSObject . AdapterGetFirstMemberOrDefaultDelegate < PSMemberInfo >,
2018-09-25 21:27:43 -07:00
shouldReplicateWhenReturning : false ,
shouldCloneWhenReturning : false ,
collectionNameForTracing : "adapted members" ));
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
if (( viewType & PSMemberViewTypes . Base ) == PSMemberViewTypes . Base )
{
returnValue . Add ( new CollectionEntry < PSMemberInfo >(
PSObject . DotNetGetMembersDelegate < PSMemberInfo >,
PSObject . DotNetGetMemberDelegate < PSMemberInfo >,
2019-03-21 02:43:52 +01:00
PSObject . DotNetGetFirstMemberOrDefaultDelegate < PSMemberInfo >,
2018-09-25 21:27:43 -07:00
shouldReplicateWhenReturning : false ,
shouldCloneWhenReturning : false ,
collectionNameForTracing : "clr members" ));
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return returnValue ;
}
private static Collection < CollectionEntry < PSMethodInfo >> GetMethodCollection ()
{
2018-09-25 21:27:43 -07:00
Collection < CollectionEntry < PSMethodInfo >> returnValue = new Collection < CollectionEntry < PSMethodInfo >>
{
new CollectionEntry < PSMethodInfo >(
PSObject . TypeTableGetMembersDelegate < PSMethodInfo >,
PSObject . TypeTableGetMemberDelegate < PSMethodInfo >,
2019-03-21 02:43:52 +01:00
PSObject . TypeTableGetFirstMemberOrDefaultDelegate < PSMethodInfo >,
2018-09-25 21:27:43 -07:00
shouldReplicateWhenReturning : true ,
shouldCloneWhenReturning : true ,
collectionNameForTracing : "type table members" ),
new CollectionEntry < PSMethodInfo >(
PSObject . AdapterGetMembersDelegate < PSMethodInfo >,
PSObject . AdapterGetMemberDelegate < PSMethodInfo >,
2019-03-21 02:43:52 +01:00
PSObject . AdapterGetFirstMemberOrDefaultDelegate < PSMethodInfo >,
2018-09-25 21:27:43 -07:00
shouldReplicateWhenReturning : false ,
shouldCloneWhenReturning : false ,
collectionNameForTracing : "adapted members" ),
new CollectionEntry < PSMethodInfo >(
PSObject . DotNetGetMembersDelegate < PSMethodInfo >,
PSObject . DotNetGetMemberDelegate < PSMethodInfo >,
2019-03-21 02:43:52 +01:00
PSObject . DotNetGetFirstMemberOrDefaultDelegate < PSMethodInfo >,
2018-09-25 21:27:43 -07:00
shouldReplicateWhenReturning : false ,
shouldCloneWhenReturning : false ,
collectionNameForTracing : "clr members" )
};
2016-03-30 14:20:52 -07:00
return returnValue ;
}
/// <summary>
2017-01-16 13:31:14 -08:00
/// A collection of delegates to get Extended/Adapted/Dotnet properties based on the
2016-03-30 14:20:52 -07:00
/// <paramref name="viewType"/>
/// </summary>
/// <param name="viewType">
/// A filter to select Extended/Adapted/Dotnet view of the object
/// </param>
/// <returns></returns>
internal static Collection < CollectionEntry < PSPropertyInfo >> GetPropertyCollection (
PSMemberViewTypes viewType )
{
return GetPropertyCollection ( viewType , null );
}
/// <summary>
2017-01-16 13:31:14 -08:00
/// A collection of delegates to get Extended/Adapted/Dotnet properties based on the
2016-03-30 14:20:52 -07:00
/// <paramref name="viewType"/>
/// </summary>
/// <param name="viewType">
/// A filter to select Extended/Adapted/Dotnet view of the object
/// </param>
/// <param name="backupTypeTable">
/// Backup type table to use if there is no execution context associated with the current thread
/// </param>
/// <returns></returns>
internal static Collection < CollectionEntry < PSPropertyInfo >> GetPropertyCollection (
PSMemberViewTypes viewType ,
TypeTable backupTypeTable )
{
Collection < CollectionEntry < PSPropertyInfo >> returnValue = new Collection < CollectionEntry < PSPropertyInfo >>();
if (( viewType & PSMemberViewTypes . Extended ) == PSMemberViewTypes . Extended )
{
if ( backupTypeTable == null )
{
returnValue . Add ( new CollectionEntry < PSPropertyInfo >(
PSObject . TypeTableGetMembersDelegate < PSPropertyInfo >,
PSObject . TypeTableGetMemberDelegate < PSPropertyInfo >,
2019-03-21 02:43:52 +01:00
PSObject . TypeTableGetFirstMemberOrDefaultDelegate < PSPropertyInfo >,
2016-03-30 14:20:52 -07:00
true , true , "type table members" ));
}
else
{
returnValue . Add ( new CollectionEntry < PSPropertyInfo >(
2018-09-25 21:27:43 -07:00
msjObj => TypeTableGetMembersDelegate < PSPropertyInfo >( msjObj , backupTypeTable ),
( msjObj , name ) => TypeTableGetMemberDelegate < PSPropertyInfo >( msjObj , backupTypeTable , name ),
2019-03-21 02:43:52 +01:00
PSObject . TypeTableGetFirstMemberOrDefaultDelegate < PSPropertyInfo >,
2016-03-30 14:20:52 -07:00
true , true , "type table members" ));
}
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
if (( viewType & PSMemberViewTypes . Adapted ) == PSMemberViewTypes . Adapted )
{
returnValue . Add ( new CollectionEntry < PSPropertyInfo >(
PSObject . AdapterGetMembersDelegate < PSPropertyInfo >,
PSObject . AdapterGetMemberDelegate < PSPropertyInfo >,
2019-03-21 02:43:52 +01:00
PSObject . AdapterGetFirstMemberOrDefaultDelegate < PSPropertyInfo >,
2016-03-30 14:20:52 -07:00
false , false , "adapted members" ));
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
if (( viewType & PSMemberViewTypes . Base ) == PSMemberViewTypes . Base )
{
returnValue . Add ( new CollectionEntry < PSPropertyInfo >(
PSObject . DotNetGetMembersDelegate < PSPropertyInfo >,
PSObject . DotNetGetMemberDelegate < PSPropertyInfo >,
2019-03-21 02:43:52 +01:00
PSObject . DotNetGetFirstMemberOrDefaultDelegate < PSPropertyInfo >,
2016-03-30 14:20:52 -07:00
false , false , "clr members" ));
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return returnValue ;
}
private void CommonInitialization ( object obj )
{
Diagnostics . Assert ( obj != null , "checked by callers" );
if ( obj is PSCustomObject )
{
2019-03-21 02:43:52 +01:00
this . ImmediateBaseObjectIsEmpty = true ;
2016-03-30 14:20:52 -07:00
}
2016-07-29 13:02:49 -07:00
_immediateBaseObject = obj ;
2016-03-30 14:20:52 -07:00
var context = LocalPipeline . GetExecutionContextFromTLS ();
2018-09-25 21:27:43 -07:00
_typeTable = context ?. TypeTableWeakReference ;
2016-03-30 14:20:52 -07:00
}
#region Adapter Mappings
2016-07-29 13:02:49 -07:00
private static readonly ConcurrentDictionary < Type , AdapterSet > s_adapterMapping = new ConcurrentDictionary < Type , AdapterSet >();
private static readonly List < Func < object , AdapterSet >> s_adapterSetMappers = new List < Func < object , AdapterSet >>
2016-03-30 14:20:52 -07:00
{
MappedInternalAdapterSet
};
private static AdapterSet MappedInternalAdapterSet ( object obj )
{
2016-07-29 13:02:49 -07:00
if ( obj is PSMemberSet ) { return PSObject . s_mshMemberSetAdapter ; }
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
if ( obj is PSObject ) { return PSObject . s_mshObjectAdapter ; }
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
if ( obj is CimInstance ) { return PSObject . s_cimInstanceAdapter ; }
2018-06-21 09:57:14 -07:00
#if ! UNIX
2018-09-25 21:27:43 -07:00
if ( obj is ManagementClass ) { return PSObject . s_managementClassAdapter ; }
2018-12-23 22:20:06 -08:00
2018-09-25 21:27:43 -07:00
if ( obj is ManagementBaseObject ) { return PSObject . s_managementObjectAdapter ; }
2018-12-23 22:20:06 -08:00
2018-09-25 21:27:43 -07:00
if ( obj is DirectoryEntry ) { return PSObject . s_directoryEntryAdapter ; }
2017-07-17 11:27:01 -07:00
#endif
2018-09-25 21:27:43 -07:00
if ( obj is DataRowView ) { return PSObject . s_dataRowViewAdapter ; }
2018-12-23 22:20:06 -08:00
2018-09-25 21:27:43 -07:00
if ( obj is DataRow ) { return PSObject . s_dataRowAdapter ; }
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
if ( obj is XmlNode ) { return PSObject . s_xmlNodeAdapter ; }
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return null ;
}
/// <summary>
/// Returns the adapter corresponding to obj.GetType()
/// </summary>
2018-12-25 21:43:03 +05:00
/// <returns>The adapter set corresponding to obj.GetType().</returns>
2016-03-30 14:20:52 -07:00
internal static AdapterSet GetMappedAdapter ( object obj , TypeTable typeTable )
{
Type objectType = obj . GetType ();
2018-09-25 21:27:43 -07:00
PSObject . AdapterSet adapter = typeTable ?. GetTypeAdapter ( objectType );
2016-03-30 14:20:52 -07:00
2018-09-25 21:27:43 -07:00
if ( adapter != null )
{
// We don't cache results found via the type table because type tables may differ b/w runspaces,
// our cache is app domain wide, and the key is simply the type.
return adapter ;
2016-03-30 14:20:52 -07:00
}
2018-09-25 21:27:43 -07:00
if ( s_adapterMapping . TryGetValue ( objectType , out AdapterSet result ))
2016-03-30 14:20:52 -07:00
{
return result ;
}
2016-07-29 13:02:49 -07:00
lock ( s_adapterSetMappers )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
foreach ( var mapper in s_adapterSetMappers )
2016-03-30 14:20:52 -07:00
{
result = mapper ( obj );
if ( result != null )
{
break ;
}
}
}
if ( result == null )
{
2017-08-22 17:44:48 -07:00
if ( objectType . IsCOMObject )
2016-03-30 14:20:52 -07:00
{
// All WinRT types are COM types.
// All WinRT types would contain the TypeAttributes flag being set to WindowsRunTime.
if ( WinRTHelper . IsWinRTType ( objectType ))
{
2016-07-29 13:02:49 -07:00
result = PSObject . s_dotNetInstanceAdapterSet ;
2016-03-30 14:20:52 -07:00
}
// We are not using IsAssignableFrom because we want to avoid
// using the COM adapters for Primary Interop Assembly types
// and they derive from System.__ComObject.
// We are not using Type.Equals because System.__ComObject is
// not public.
else if ( objectType . FullName . Equals ( "System.__ComObject" ))
{
// We don't cache the adapter set for COM objects because the adapter varies depending on the COM object, but often
// (typically), the runtime type is always the same. That's why this if statement is here and returns.
ComTypeInfo info = ComTypeInfo . GetDispatchTypeInfo ( obj );
return info != null
2019-03-21 02:43:52 +01:00
? new AdapterSet ( new ComAdapter ( info ), DotNetInstanceAdapter )
2016-07-29 13:02:49 -07:00
: PSObject . s_dotNetInstanceAdapterSet ;
2016-03-30 14:20:52 -07:00
}
else
{
ComTypeInfo info = ComTypeInfo . GetDispatchTypeInfo ( obj );
result = info != null
? new AdapterSet ( new DotNetAdapterWithComTypeName ( info ), null )
2016-07-29 13:02:49 -07:00
: PSObject . s_dotNetInstanceAdapterSet ;
2016-03-30 14:20:52 -07:00
}
}
else
{
2016-07-29 13:02:49 -07:00
result = PSObject . s_dotNetInstanceAdapterSet ;
2016-03-30 14:20:52 -07:00
}
}
2016-07-29 13:02:49 -07:00
var existingOrNew = s_adapterMapping . GetOrAdd ( objectType , result );
2016-03-30 14:20:52 -07:00
Diagnostics . Assert ( existingOrNew == result , "There is a logic error in caching adapter sets." );
return result ;
}
#endregion
internal static AdapterSet CreateThirdPartyAdapterSet ( Type adaptedType , PSPropertyAdapter adapter )
{
2016-07-29 13:02:49 -07:00
return new AdapterSet ( new ThirdPartyAdapter ( adaptedType , adapter ), s_baseAdapterForAdaptedObjects );
2016-03-30 14:20:52 -07:00
}
#endregion private to the constructors
/// <summary>
2019-01-06 04:40:24 +05:00
/// Initializes a new instance of PSObject with an PSCustomObject BaseObject.
2016-03-30 14:20:52 -07:00
/// </summary>
public PSObject ()
{
CommonInitialization ( PSCustomObject . SelfInstance );
}
2018-08-06 19:58:55 +02:00
/// <summary>
/// Initializes a new instance of PSObject with an PSCustomObject BaseObject
2019-01-06 04:40:24 +05:00
/// with an initial capacity for members.
2018-08-06 19:58:55 +02:00
/// </summary>
/// <param name="instanceMemberCapacity">The initial capacity for the instance member collection.</param>
public PSObject ( int instanceMemberCapacity ) : this ()
{
_instanceMembers = new PSMemberInfoInternalCollection < PSMemberInfo >( instanceMemberCapacity );
}
2016-03-30 14:20:52 -07:00
/// <summary>
/// Initializes a new instance of PSObject wrapping obj (accessible through BaseObject).
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="obj">Object we are wrapping.</param>
/// <exception cref="ArgumentNullException">If <paramref name="obj"/> is null.</exception>
2016-03-30 14:20:52 -07:00
[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "This is shipped as part of V1. Retaining this for backward compatibility.")]
2016-07-29 13:02:49 -07:00
public PSObject ( object obj )
2016-03-30 14:20:52 -07:00
{
if ( obj == null )
{
throw PSTraceSource . NewArgumentNullException ( "obj" );
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
CommonInitialization ( obj );
}
/// <summary>
2019-01-06 04:40:24 +05:00
/// Creates a PSObject from an ISerializable context.
2016-03-30 14:20:52 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="info">Serialization information for this instance.</param>
/// <param name="context">The streaming context for this instance.</param>
2016-03-30 14:20:52 -07:00
protected PSObject ( SerializationInfo info , StreamingContext context )
{
if ( info == null )
{
throw PSTraceSource . NewArgumentNullException ( "info" );
}
string serializedData = info . GetValue ( "CliXml" , typeof ( string )) as string ;
if ( serializedData == null )
{
throw PSTraceSource . NewArgumentNullException ( "info" );
}
PSObject result = PSObject . AsPSObject ( PSSerializer . Deserialize ( serializedData ));
CommonInitialization ( result . ImmediateBaseObject );
CopyDeserializerFields ( source : result , target : this );
}
internal static PSObject ConstructPSObjectFromSerializationInfo ( SerializationInfo info , StreamingContext context )
{
return new PSObject ( info , context );
}
#endregion constructors
#region fields
#region instance fields
2019-03-21 02:43:52 +01:00
private readonly object _lockObject = new object ();
private ConsolidatedString _typeNames ;
2016-03-30 14:20:52 -07:00
/// <summary>
/// This is the main field in the class representing
2019-01-06 04:40:24 +05:00
/// the System.Object we are encapsulating.
2016-03-30 14:20:52 -07:00
/// </summary>
2016-07-29 13:02:49 -07:00
private object _immediateBaseObject ;
2016-03-30 14:20:52 -07:00
private WeakReference < TypeTable > _typeTable ;
2019-03-21 02:43:52 +01:00
private AdapterSet _adapterSet ;
private PSMemberInfoInternalCollection < PSMemberInfo > _instanceMembers ;
private PSMemberInfoIntegratingCollection < PSMemberInfo > _members ;
private PSMemberInfoIntegratingCollection < PSPropertyInfo > _properties ;
private PSMemberInfoIntegratingCollection < PSMethodInfo > _methods ;
private PSObjectFlags _flags ;
#endregion instance fields
private static readonly PSTraceSource s_memberResolution = PSTraceSource . GetTracer ( "MemberResolution" , "Traces the resolution from member name to the member. A member can be a property, method, etc." , false );
private static readonly ConditionalWeakTable < object , ConsolidatedString > s_typeNamesResurrectionTable = new ConditionalWeakTable < object , ConsolidatedString >();
private static readonly Collection < CollectionEntry < PSMemberInfo >> s_memberCollection = GetMemberCollection ( PSMemberViewTypes . All );
private static readonly Collection < CollectionEntry < PSMethodInfo >> s_methodCollection = GetMethodCollection ();
private static readonly Collection < CollectionEntry < PSPropertyInfo >> s_propertyCollection = GetPropertyCollection ( PSMemberViewTypes . All );
private static readonly DotNetAdapter s_dotNetInstanceAdapter = new DotNetAdapter ();
private static readonly DotNetAdapter s_baseAdapterForAdaptedObjects = new BaseDotNetAdapterForAdaptedObjects ();
private static readonly DotNetAdapter s_dotNetStaticAdapter = new DotNetAdapter ( true );
private static readonly AdapterSet s_dotNetInstanceAdapterSet = new AdapterSet ( DotNetInstanceAdapter , null );
private static readonly AdapterSet s_mshMemberSetAdapter = new AdapterSet ( new PSMemberSetAdapter (), null );
private static readonly AdapterSet s_mshObjectAdapter = new AdapterSet ( new PSObjectAdapter (), null );
private static readonly PSObject . AdapterSet s_cimInstanceAdapter =
new PSObject . AdapterSet ( new ThirdPartyAdapter ( typeof ( Microsoft . Management . Infrastructure . CimInstance ),
new Microsoft . PowerShell . Cim . CimInstanceAdapter ()),
PSObject . DotNetInstanceAdapter );
#if ! UNIX
private static readonly AdapterSet s_managementObjectAdapter = new AdapterSet ( new ManagementObjectAdapter (), DotNetInstanceAdapter );
private static readonly AdapterSet s_managementClassAdapter = new AdapterSet ( new ManagementClassApdapter (), DotNetInstanceAdapter );
private static readonly AdapterSet s_directoryEntryAdapter = new AdapterSet ( new DirectoryEntryAdapter (), DotNetInstanceAdapter );
#endif
private static readonly AdapterSet s_dataRowViewAdapter = new AdapterSet ( new DataRowViewAdapter (), s_baseAdapterForAdaptedObjects );
private static readonly AdapterSet s_dataRowAdapter = new AdapterSet ( new DataRowAdapter (), s_baseAdapterForAdaptedObjects );
private static readonly AdapterSet s_xmlNodeAdapter = new AdapterSet ( new XmlNodeAdapter (), s_baseAdapterForAdaptedObjects );
#endregion fields
#region properties
internal PSMemberInfoInternalCollection < PSMemberInfo > InstanceMembers
{
get
{
if ( _instanceMembers == null )
{
lock ( _lockObject )
{
if ( _instanceMembers == null )
{
_instanceMembers =
s_instanceMembersResurrectionTable . GetValue (
GetKeyForResurrectionTables ( this ),
_ => new PSMemberInfoInternalCollection < PSMemberInfo >());
}
}
}
return _instanceMembers ;
}
set => _instanceMembers = value ;
}
2016-03-30 14:20:52 -07:00
/// <summary>
/// This is the adapter that will depend on the type of baseObject.
/// </summary>
2019-03-21 02:43:52 +01:00
internal Adapter InternalAdapter => InternalAdapterSet . OriginalAdapter ;
2016-03-30 14:20:52 -07:00
/// <summary>
/// This is the adapter that is used to resolve the base dotnet members for an
/// adapted object. If an object is not adapted, this will be null.
/// </summary>
/// <remarks>
/// If an object is not adapted, InternalAdapter will use the dotnet adapter.
/// So there is no point falling back to the same dotnet adapter.
2017-01-16 13:31:14 -08:00
///
2016-03-30 14:20:52 -07:00
/// If an object is adapted, this adapter will be used to resolve the dotnet
/// members.
/// </remarks>
2018-09-25 21:27:43 -07:00
internal Adapter InternalBaseDotNetAdapter => InternalAdapterSet . DotNetAdapter ;
2016-03-30 14:20:52 -07:00
/// <summary>
2017-01-16 13:31:14 -08:00
/// This is the adapter set that will contain the adapter of the baseObject
2016-08-28 05:44:55 +00:00
/// and the ultimate .net member lookup adapter.
2016-03-30 14:20:52 -07:00
/// See <see cref="PSObject.AdapterSet"/> for explanation.
/// </summary>
private AdapterSet InternalAdapterSet
{
get
{
2018-06-26 02:37:09 +05:00
if ( _adapterSet == null )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
lock ( _lockObject )
2016-03-30 14:20:52 -07:00
{
2018-06-26 02:37:09 +05:00
if ( _adapterSet == null )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
_adapterSet = GetMappedAdapter ( _immediateBaseObject , GetTypeTable ());
2016-03-30 14:20:52 -07:00
}
}
}
2016-07-29 13:02:49 -07:00
return _adapterSet ;
2016-03-30 14:20:52 -07:00
}
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
/// <summary>
2019-01-06 04:40:24 +05:00
/// Gets the member collection.
2016-03-30 14:20:52 -07:00
/// </summary>
public PSMemberInfoCollection < PSMemberInfo > Members
{
get
{
2016-07-29 13:02:49 -07:00
if ( _members == null )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
lock ( _lockObject )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
if ( _members == null )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
_members = new PSMemberInfoIntegratingCollection < PSMemberInfo >( this , s_memberCollection );
}
2016-03-30 14:20:52 -07:00
}
}
return _members ;
}
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
/// <summary>
/// Gets the Property collection, or the members that are actually properties.
/// </summary>
public PSMemberInfoCollection < PSPropertyInfo > Properties
{
get
{
2016-07-29 13:02:49 -07:00
if ( _properties == null )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
lock ( _lockObject )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
if ( _properties == null )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
_properties = new PSMemberInfoIntegratingCollection < PSPropertyInfo >( this , s_propertyCollection );
}
2016-03-30 14:20:52 -07:00
}
}
return _properties ;
}
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
/// <summary>
/// Gets the Method collection, or the members that are actually methods.
/// </summary>
public PSMemberInfoCollection < PSMethodInfo > Methods
{
get
{
2016-07-29 13:02:49 -07:00
if ( _methods == null )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
lock ( _lockObject )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
if ( _methods == null )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
_methods = new PSMemberInfoIntegratingCollection < PSMethodInfo >( this , s_methodCollection );
}
2016-03-30 14:20:52 -07:00
}
}
return _methods ;
}
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
/// <summary>
/// Gets the object we are directly wrapping.
/// </summary>
2017-01-16 13:31:14 -08:00
/// <remarks>If the ImmediateBaseObject is another PSObject,
2016-03-30 14:20:52 -07:00
/// that PSObject will be returned.</remarks>
2018-09-25 21:27:43 -07:00
public object ImmediateBaseObject => _immediateBaseObject ;
2016-03-30 14:20:52 -07:00
/// <summary>
/// Gets the object we are wrapping.
/// </summary>
/// <remarks>If the ImmediateBaseObject is another PSObject, this property
/// will return its BaseObject.</remarks>
public object BaseObject
{
get
{
2018-09-25 21:27:43 -07:00
object returnValue ;
2016-03-30 14:20:52 -07:00
PSObject mshObj = this ;
do
{
2016-07-29 13:02:49 -07:00
returnValue = mshObj . _immediateBaseObject ;
2016-03-30 14:20:52 -07:00
mshObj = returnValue as PSObject ;
} while ( mshObj != null );
return returnValue ;
}
}
/// <summary>
/// Gets the type names collection initially containing the object type hierarchy.
/// </summary>
public Collection < string > TypeNames
{
get
{
var result = InternalTypeNames ;
if ( result . IsReadOnly )
{
2016-07-29 13:02:49 -07:00
lock ( _lockObject )
2016-03-30 14:20:52 -07:00
{
// Check again after acquiring the lock to ensure some other thread didn't make the copy.
if ( result . IsReadOnly )
{
2016-07-29 13:02:49 -07:00
_typeNames = s_typeNamesResurrectionTable . GetValue (
2016-03-30 14:20:52 -07:00
GetKeyForResurrectionTables ( this ),
_ => new ConsolidatedString ( _typeNames ));
object baseObj = BaseObject ;
// In most cases, the TypeNames will be modified after it's returned
if ( baseObj != null ) { PSVariableAssignmentBinder . NoteTypeHasInstanceMemberOrTypeName ( baseObj . GetType ()); }
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return _typeNames ;
}
}
}
return result ;
}
}
internal ConsolidatedString InternalTypeNames
{
get
{
2016-07-29 13:02:49 -07:00
if ( _typeNames == null )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
lock ( _lockObject )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
if ( _typeNames == null )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
if (! s_typeNamesResurrectionTable . TryGetValue ( GetKeyForResurrectionTables ( this ), out _typeNames ))
2016-03-30 14:20:52 -07:00
{
// We don't cache this typename in the resurrection table because it's cached in the psobject,
// and the assumption is we'll usually get the value directly from the PSObject, so it's not
// needed in the resurrection table.
//
// If we hand out the typename to a client that could change it (through the public property
// TypeNames), then we'll need to store the copy in the resurrection table.
2016-07-29 13:02:49 -07:00
_typeNames = InternalAdapter . BaseGetTypeNameHierarchy ( _immediateBaseObject );
2016-03-30 14:20:52 -07:00
}
}
}
}
return _typeNames ;
}
2018-12-23 22:20:06 -08:00
2018-09-25 21:27:43 -07:00
set => _typeNames = value ;
2016-03-30 14:20:52 -07:00
}
internal static ConsolidatedString GetTypeNames ( object obj )
{
2018-09-25 21:27:43 -07:00
if ( obj is PSObject psobj )
2016-03-30 14:20:52 -07:00
{
return psobj . InternalTypeNames ;
}
2018-09-25 21:27:43 -07:00
if ( HasInstanceTypeName ( obj , out ConsolidatedString result ))
2016-03-30 14:20:52 -07:00
{
return result ;
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return PSObject . GetMappedAdapter ( obj , null ). OriginalAdapter . BaseGetTypeNameHierarchy ( obj );
}
internal static bool HasInstanceTypeName ( object obj , out ConsolidatedString result )
{
2016-07-29 13:02:49 -07:00
return s_typeNamesResurrectionTable . TryGetValue ( GetKeyForResurrectionTables ( obj ), out result );
2016-03-30 14:20:52 -07:00
}
#endregion properties
#region static methods
2019-03-21 02:43:52 +01:00
internal static bool HasInstanceMembers ( object obj , out PSMemberInfoInternalCollection < PSMemberInfo > instanceMembers )
{
if ( obj is PSObject psobj )
{
lock ( psobj )
{
if ( psobj . _instanceMembers == null )
{
s_instanceMembersResurrectionTable . TryGetValue ( GetKeyForResurrectionTables ( psobj ), out psobj . _instanceMembers );
}
}
instanceMembers = psobj . _instanceMembers ;
}
else if ( obj != null )
{
s_instanceMembersResurrectionTable . TryGetValue ( GetKeyForResurrectionTables ( obj ), out instanceMembers );
}
else
{
instanceMembers = null ;
}
return instanceMembers != null && instanceMembers . Count > 0 ;
}
private static readonly ConditionalWeakTable < object , PSMemberInfoInternalCollection < PSMemberInfo >> s_instanceMembersResurrectionTable =
new ConditionalWeakTable < object , PSMemberInfoInternalCollection < PSMemberInfo >>();
2016-03-30 14:20:52 -07:00
/// <summary>
/// </summary>
/// <param name="valueToConvert"></param>
/// <returns></returns>
public static implicit operator PSObject ( int valueToConvert )
{
return PSObject . AsPSObject ( valueToConvert );
}
/// <summary>
/// </summary>
/// <param name="valueToConvert"></param>
/// <returns></returns>
public static implicit operator PSObject ( string valueToConvert )
{
return PSObject . AsPSObject ( valueToConvert );
}
/// <summary>
/// </summary>
/// <param name="valueToConvert"></param>
/// <returns></returns>
public static implicit operator PSObject ( Hashtable valueToConvert )
{
return PSObject . AsPSObject ( valueToConvert );
}
/// <summary>
/// </summary>
/// <param name="valueToConvert"></param>
/// <returns></returns>
public static implicit operator PSObject ( double valueToConvert )
{
return PSObject . AsPSObject ( valueToConvert );
}
/// <summary>
/// </summary>
/// <param name="valueToConvert"></param>
/// <returns></returns>
public static implicit operator PSObject ( bool valueToConvert )
{
return PSObject . AsPSObject ( valueToConvert );
}
/// <summary>
2017-01-16 13:31:14 -08:00
/// If obj is not an PSObject, it is returned. Otherwise, retrieves
2016-03-30 14:20:52 -07:00
/// the first non PSObject or PSObject with CustomBaseObject
/// in the PSObject - BaseObject chain.
/// </summary>
internal static object Base ( object obj )
{
PSObject mshObj = obj as PSObject ;
if ( mshObj == null )
{
return obj ;
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
if ( mshObj == AutomationNull . Value )
return null ;
2019-03-21 02:43:52 +01:00
if ( mshObj . ImmediateBaseObjectIsEmpty )
2016-03-30 14:20:52 -07:00
{
return obj ;
}
2018-12-23 22:20:06 -08:00
2018-09-25 21:27:43 -07:00
object returnValue ;
2016-03-30 14:20:52 -07:00
do
{
2016-07-29 13:02:49 -07:00
returnValue = mshObj . _immediateBaseObject ;
2016-03-30 14:20:52 -07:00
mshObj = returnValue as PSObject ;
2019-03-21 02:43:52 +01:00
} while (( mshObj != null ) && (! mshObj . ImmediateBaseObjectIsEmpty ));
2016-03-30 14:20:52 -07:00
return returnValue ;
}
internal static PSMemberInfo GetStaticCLRMember ( object obj , string methodName )
{
obj = PSObject . Base ( obj );
if ( obj == null || methodName == null || methodName . Length == 0 )
{
return null ;
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
var objType = obj as Type ?? obj . GetType ();
2019-03-21 02:43:52 +01:00
return DotNetStaticAdapter . BaseGetMember < PSMemberInfo >( objType , methodName );
2016-03-30 14:20:52 -07:00
}
/// <summary>
/// If obj is an PSObject it will be returned as is, otherwise
/// a new PSObject will be created based on obj.
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="obj">Object to be wrapped.</param>
2016-03-30 14:20:52 -07:00
/// <returns>
/// obj or a new PSObject whose BaseObject is obj
/// </returns>
2018-12-29 08:25:49 +05:00
/// <exception cref="ArgumentNullException">If <paramref name="obj"/> is null.</exception>
2016-03-30 14:20:52 -07:00
[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "This is shipped as part of V1. Retaining this for backward compatibility.")]
public static PSObject AsPSObject ( object obj )
{
return AsPSObject ( obj , false );
}
/// <summary>
/// If obj is a PSObject, it will be returned as is, otherwise a new
/// PSObject will be created on obj. Its InstanceMembers and TypeNames
/// will be initialized if we are not going to use the ResurrectionTables
/// for this PSObject instance.
/// </summary>
/// <param name="obj"></param>
/// <param name="storeTypeNameAndInstanceMembersLocally"></param>
/// <returns></returns>
[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "AsPSObject is shipped as part of V1. This is a new overload method.")]
internal static PSObject AsPSObject ( object obj , bool storeTypeNameAndInstanceMembersLocally )
{
if ( obj == null )
{
throw PSTraceSource . NewArgumentNullException ( "obj" );
}
2018-09-25 21:27:43 -07:00
if ( obj is PSObject so )
2016-03-30 14:20:52 -07:00
{
return so ;
}
2019-03-21 02:43:52 +01:00
return new PSObject ( obj ) { StoreTypeNameAndInstanceMembersLocally = storeTypeNameAndInstanceMembersLocally };
2016-03-30 14:20:52 -07:00
}
/// <summary>
/// Returns an object that should be used as a key for getting 1) instance members and 2) type names
/// - If base object is a PSCustomObject or a string or a type
/// then the most nested wrapping PSObject is returned (the PSObject where immediateBaseObject=PSCustomObject/string/type)
/// - Otherwise the base object is returned
/// This is a temporary fix for Win8 : 254345 - Job Failed By Throwing ExtendedTypeSystemException.
/// </summary>
/// <returns></returns>
internal static object GetKeyForResurrectionTables ( object obj )
{
var pso = obj as PSObject ;
if ( pso == null )
{
return obj ;
}
PSObject psObjectAboveBase = pso ;
while ( psObjectAboveBase . ImmediateBaseObject is PSObject )
{
psObjectAboveBase = ( PSObject ) psObjectAboveBase . ImmediateBaseObject ;
}
if ( psObjectAboveBase . ImmediateBaseObject is PSCustomObject
|| psObjectAboveBase . ImmediateBaseObject is string
2019-03-21 02:43:52 +01:00
|| pso . StoreTypeNameAndInstanceMembersLocally )
2016-03-30 14:20:52 -07:00
{
return psObjectAboveBase ;
}
return psObjectAboveBase . ImmediateBaseObject ;
}
#endregion static methods
#region instance methods
#region ToString
private static string GetSeparator ( ExecutionContext context , string separator )
{
if ( separator != null )
{
return separator ;
}
2018-09-25 21:27:43 -07:00
object obj = context ?. GetVariableValue ( SpecialVariables . OFSVarPath );
if ( obj != null )
2016-03-30 14:20:52 -07:00
{
2018-09-25 21:27:43 -07:00
return obj . ToString ();
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return " " ;
}
internal static string ToStringEnumerator ( ExecutionContext context , IEnumerator enumerator , string separator , string format , IFormatProvider formatProvider )
{
StringBuilder returnValue = new StringBuilder ();
string separatorToUse = GetSeparator ( context , separator );
while ( enumerator . MoveNext ())
{
object obj = enumerator . Current ;
returnValue . Append ( PSObject . ToString ( context , obj , separator , format , formatProvider , false , false ));
returnValue . Append ( separatorToUse );
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
if ( returnValue . Length == 0 )
{
2018-09-25 21:27:43 -07:00
return string . Empty ;
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
int separatorLength = separatorToUse . Length ;
returnValue . Remove ( returnValue . Length - separatorLength , separatorLength );
return returnValue . ToString ();
}
internal static string ToStringEnumerable ( ExecutionContext context , IEnumerable enumerable , string separator , string format , IFormatProvider formatProvider )
{
StringBuilder returnValue = new StringBuilder ();
string separatorToUse = GetSeparator ( context , separator );
foreach ( object obj in enumerable )
{
if ( obj != null )
{
PSObject mshObj = PSObject . AsPSObject ( obj );
returnValue . Append ( PSObject . ToString ( context , mshObj , separator , format , formatProvider , false , false ));
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
returnValue . Append ( separatorToUse );
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
if ( returnValue . Length == 0 )
{
2018-09-25 21:27:43 -07:00
return string . Empty ;
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
int separatorLength = separatorToUse . Length ;
returnValue . Remove ( returnValue . Length - separatorLength , separatorLength );
return returnValue . ToString ();
}
private static string ToStringEmptyBaseObject ( ExecutionContext context , PSObject mshObj , string separator , string format , IFormatProvider formatProvider )
{
StringBuilder returnValue = new StringBuilder ( "@{" );
bool isFirst = true ;
foreach ( PSPropertyInfo property in mshObj . Properties )
{
if (! isFirst )
{
returnValue . Append ( "; " );
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
isFirst = false ;
returnValue . Append ( property . Name );
returnValue . Append ( "=" );
// Don't evaluate script properties during a ToString() operation.
2018-09-25 21:27:43 -07:00
var propertyValue = property is PSScriptProperty ? property . GetType (). FullName : property . Value ;
2016-03-30 14:20:52 -07:00
returnValue . Append ( PSObject . ToString ( context , propertyValue , separator , format , formatProvider , false , false ));
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
if ( isFirst )
{
return string . Empty ;
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
returnValue . Append ( "}" );
return returnValue . ToString ();
}
/// <summary>
/// Returns the string representation of obj.
/// </summary>
2018-12-28 11:05:14 +05:00
/// <param name="context">ExecutionContext used to fetch the separator.</param>
2016-03-30 14:20:52 -07:00
/// <param name="obj">
/// object we are trying to call ToString on. If this is not an PSObject we try
/// enumerating and if that fails we call obj.ToString.
2017-01-16 13:31:14 -08:00
/// If this is an PSObject, we look for a brokered ToString.
2016-03-30 14:20:52 -07:00
/// If it is not present, and the BaseObject is null we try listing the properties.
2016-08-28 05:44:55 +00:00
/// If the BaseObject is not null we try enumerating. If that fails we try the BaseObject's ToString.
2016-03-30 14:20:52 -07:00
/// </param>
2018-12-25 21:43:03 +05:00
/// <returns>A string representation of the object.</returns>
2016-03-30 14:20:52 -07:00
/// <exception cref="ExtendedTypeSystemException">
/// When there is a brokered ToString but it failed, or when the ToString on obj throws an exception.
/// </exception>
internal static string ToStringParser ( ExecutionContext context , object obj )
2018-11-14 22:52:44 +01:00
{
return ToStringParser ( context , obj , CultureInfo . InvariantCulture );
}
/// <summary>
/// Returns the string representation of obj.
/// </summary>
2018-12-28 11:05:14 +05:00
/// <param name="context">ExecutionContext used to fetch the separator.</param>
2018-11-14 22:52:44 +01:00
/// <param name="obj">
/// object we are trying to call ToString on. If this is not an PSObject we try
/// enumerating and if that fails we call obj.ToString.
/// If this is an PSObject, we look for a brokered ToString.
/// If it is not present, and the BaseObject is null we try listing the properties.
/// If the BaseObject is not null we try enumerating. If that fails we try the BaseObject's ToString.
/// </param>
/// <param name="formatProvider">The formatProvider to be passed to ToString.</param>
/// <returns>A string representation of the object.</returns>
/// <exception cref="ExtendedTypeSystemException">
/// When there is a brokered ToString but it failed, or when the ToString on obj throws an exception.
/// </exception>
internal static string ToStringParser ( ExecutionContext context , object obj , IFormatProvider formatProvider )
2016-03-30 14:20:52 -07:00
{
try
{
2018-11-14 22:52:44 +01:00
return ToString ( context , obj , null , null , formatProvider , true , true );
2016-03-30 14:20:52 -07:00
}
catch ( ExtendedTypeSystemException etse )
{
throw new PSInvalidCastException ( "InvalidCastFromAnyTypeToString" , etse . InnerException ,
ExtendedTypeSystem . InvalidCastCannotRetrieveString );
}
}
/// <summary>
2019-01-06 04:40:24 +05:00
/// Called from an PSObject instance ToString to provide a string representation for an object.
2016-03-30 14:20:52 -07:00
/// </summary>
/// <param name="context">
2017-01-16 13:31:14 -08:00
/// ExecutionContext used to fetch the separator.
2016-03-30 14:20:52 -07:00
/// Typically either this or separator will be null.
/// If both are null, " " is used.
/// </param>
/// <param name="obj">
/// object we are trying to call ToString on. If this is not an PSObject we try
/// enumerating and if that fails we call obj.ToString.
2017-01-16 13:31:14 -08:00
/// If this is an PSObject, we look for a brokered ToString.
2016-03-30 14:20:52 -07:00
/// If it is not present, and the BaseObject is null we try listing the properties.
2016-08-28 05:44:55 +00:00
/// If the BaseObject is not null we try enumerating. If that fails we try the BaseObject's ToString.
2016-03-30 14:20:52 -07:00
/// </param>
2018-12-28 16:39:06 +05:00
/// <param name="separator">The separator between elements, if this is an enumeration.</param>
2018-12-29 08:25:49 +05:00
/// <param name="format">The format to be passed to ToString.</param>
/// <param name="formatProvider">The formatProvider to be passed to ToString.</param>
2016-03-30 14:20:52 -07:00
/// <param name="recurse">true if we should enumerate values or properties which would cause recursive
/// calls to this method. Such recursive calls will have recurse set to false, limiting the depth.</param>
/// <param name="unravelEnumeratorOnRecurse">If recurse is false, this parameter is not considered. If it is true
/// this parameter will determine how enumerators are going to be treated.
/// </param>
2018-12-25 21:43:03 +05:00
/// <returns>A string representation of the object.</returns>
2016-03-30 14:20:52 -07:00
/// <exception cref="ExtendedTypeSystemException">
/// When there is a brokered ToString but it failed, or when the ToString on obj throws an exception.
/// </exception>
internal static string ToString ( ExecutionContext context , object obj , string separator , string format , IFormatProvider formatProvider , bool recurse , bool unravelEnumeratorOnRecurse )
{
2019-06-18 20:56:43 -07:00
bool TryFastTrackPrimitiveTypes ( object value , out string str )
{
switch ( Convert . GetTypeCode ( value ))
{
case TypeCode . String :
str = ( string ) value ;
break ;
case TypeCode . Byte :
case TypeCode . SByte :
case TypeCode . Int16 :
case TypeCode . UInt16 :
case TypeCode . Int32 :
case TypeCode . UInt32 :
case TypeCode . Int64 :
case TypeCode . UInt64 :
case TypeCode . DateTime :
case TypeCode . Decimal :
var formattable = ( IFormattable ) value ;
str = formattable . ToString ( format , formatProvider );
break ;
case TypeCode . Double :
var dbl = ( double ) value ;
str = dbl . ToString ( format ?? LanguagePrimitives . DoublePrecision , formatProvider );
break ;
case TypeCode . Single :
var sgl = ( float ) value ;
str = sgl . ToString ( format ?? LanguagePrimitives . SinglePrecision , formatProvider );
break ;
default :
str = null ;
return false ;
}
return true ;
}
2016-03-30 14:20:52 -07:00
PSObject mshObj = obj as PSObject ;
#region plain object
if ( mshObj == null )
{
if ( obj == null )
{
2018-09-25 21:27:43 -07:00
return string . Empty ;
2016-03-30 14:20:52 -07:00
}
2019-06-18 20:56:43 -07:00
if ( TryFastTrackPrimitiveTypes ( obj , out string objString ))
2016-03-30 14:20:52 -07:00
{
2019-06-18 20:56:43 -07:00
return objString ;
2016-03-30 14:20:52 -07:00
}
2016-07-29 13:02:49 -07:00
2016-03-30 14:20:52 -07:00
#region recurse
if ( recurse )
{
IEnumerable enumerable = LanguagePrimitives . GetEnumerable ( obj );
if ( enumerable != null )
{
try
{
return ToStringEnumerable ( context , enumerable , separator , format , formatProvider );
}
2016-11-01 15:24:07 -07:00
catch ( Exception )
2016-03-30 14:20:52 -07:00
{
// We do want to ignore exceptions here to try the regular ToString below.
}
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
if ( unravelEnumeratorOnRecurse )
{
IEnumerator enumerator = LanguagePrimitives . GetEnumerator ( obj );
if ( enumerator != null )
{
try
{
return ToStringEnumerator ( context , enumerator , separator , format , formatProvider );
}
2016-11-01 15:24:07 -07:00
catch ( Exception )
2016-03-30 14:20:52 -07:00
{
// We do want to ignore exceptions here to try the regular ToString below.
}
}
}
}
#endregion recurse
#region object ToString
IFormattable objFormattable = obj as IFormattable ;
try
{
if ( objFormattable == null )
{
Type type = obj as Type ;
if ( type != null )
{
return Microsoft . PowerShell . ToStringCodeMethods . Type ( type );
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return obj . ToString ();
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return objFormattable . ToString ( format , formatProvider );
}
catch ( Exception e )
{
throw new ExtendedTypeSystemException ( "ToStringObjectBasicException" , e ,
ExtendedTypeSystem . ToStringException , e . Message );
}
#endregion object ToString
2016-07-29 13:02:49 -07:00
}
2016-03-30 14:20:52 -07:00
#endregion plain object
#region PSObject
#region brokered ToString
// A brokered ToString has precedence over any other attempts.
// If it fails we let the exception go because the caller must be notified.
PSMethodInfo method = null ;
2018-09-25 21:27:43 -07:00
if ( PSObject . HasInstanceMembers ( mshObj , out PSMemberInfoInternalCollection < PSMemberInfo > instanceMembers ))
2016-03-30 14:20:52 -07:00
{
method = instanceMembers [ "ToString" ] as PSMethodInfo ;
}
if ( method == null )
{
if ( mshObj . InternalTypeNames . Count != 0 )
{
TypeTable table = mshObj . GetTypeTable ();
if ( table != null )
{
method = table . GetMembers < PSMethodInfo >( mshObj . InternalTypeNames )[ "ToString" ];
if ( method != null )
{
method = ( PSMethodInfo ) method . Copy ();
method . instance = mshObj ;
}
}
}
}
if ( method != null )
{
try
{
// Even if a format specifier has been provided, if there is only one overload
// then it can't take a format specified...
2018-09-25 21:27:43 -07:00
object retObj ;
2016-03-30 14:20:52 -07:00
if ( formatProvider != null && method . OverloadDefinitions . Count > 1 )
{
retObj = method . Invoke ( format , formatProvider );
return retObj != null ? retObj . ToString () : string . Empty ;
}
retObj = method . Invoke ();
return retObj != null ? retObj . ToString () : string . Empty ;
}
catch ( MethodException e )
{
throw new ExtendedTypeSystemException ( "MethodExceptionNullFormatProvider" , e ,
ExtendedTypeSystem . ToStringException , e . Message );
}
}
#endregion brokered ToString
#region recurse
// Since we don't have a brokered ToString, we check for the need to enumerate the object or its properties
if ( recurse )
{
2019-03-21 02:43:52 +01:00
if ( mshObj . ImmediateBaseObjectIsEmpty )
2016-03-30 14:20:52 -07:00
{
try
{
return PSObject . ToStringEmptyBaseObject ( context , mshObj , separator , format , formatProvider );
}
2016-11-01 15:24:07 -07:00
catch ( Exception )
2016-03-30 14:20:52 -07:00
{
// We do want to ignore exceptions here to try the regular ToString below.
}
}
IEnumerable enumerable = LanguagePrimitives . GetEnumerable ( mshObj );
if ( enumerable != null )
{
try
{
return ToStringEnumerable ( context , enumerable , separator , format , formatProvider );
}
2016-11-01 15:24:07 -07:00
catch ( Exception )
2016-03-30 14:20:52 -07:00
{
// We do want to ignore exceptions here to try the regular ToString below.
}
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
if ( unravelEnumeratorOnRecurse )
{
IEnumerator enumerator = LanguagePrimitives . GetEnumerator ( mshObj );
if ( enumerator != null )
{
try
{
return ToStringEnumerator ( context , enumerator , separator , format , formatProvider );
}
2016-11-01 15:24:07 -07:00
catch ( Exception )
2016-03-30 14:20:52 -07:00
{
// We do want to ignore exceptions here to try the regular ToString below.
}
}
}
}
#endregion recurse
#region mshObject ' s BaseObject ToString
// If we've cached a string representation for this object, use that. This
// is used to preserve the original string for numeric literals.
if ( mshObj . TokenText != null )
{
return mshObj . TokenText ;
}
// Since we don't have a brokered ToString and the enumerations were not necessary or failed
// we try the BaseObject's ToString
2016-07-29 13:02:49 -07:00
object baseObject = mshObj . _immediateBaseObject ;
2019-06-18 20:56:43 -07:00
if ( TryFastTrackPrimitiveTypes ( baseObject , out string baseObjString ))
{
return baseObjString ;
}
2016-03-30 14:20:52 -07:00
IFormattable msjObjFormattable = baseObject as IFormattable ;
try
{
2018-09-25 21:27:43 -07:00
var result = msjObjFormattable == null ? baseObject . ToString () : msjObjFormattable . ToString ( format , formatProvider );
2016-03-30 14:20:52 -07:00
2018-09-25 21:27:43 -07:00
return result ?? string . Empty ;
2016-03-30 14:20:52 -07:00
}
catch ( Exception e )
{
throw new ExtendedTypeSystemException ( "ToStringPSObjectBasicException" , e ,
ExtendedTypeSystem . ToStringException , e . Message );
}
#endregion mshObject ' s BaseObject ToString
#endregion PSObject
}
/// <summary>
/// Returns the string representation for this object. A ToString
/// CodeMethod or ScriptMethod will be used, if available. Enumerations items are
/// concatenated using $ofs.
/// </summary>
2018-12-25 21:43:03 +05:00
/// <returns>The string representation for baseObject.</returns>
2018-12-29 08:25:49 +05:00
/// <exception cref="ExtendedTypeSystemException">If an exception was thrown by the BaseObject's ToString.</exception>
2016-03-30 14:20:52 -07:00
public override string ToString ()
{
2019-01-06 06:51:20 +05:00
// If ToString value from deserialization is available,
// simply return it.
2019-03-21 02:43:52 +01:00
if ( ToStringFromDeserialization != null )
2016-07-29 13:02:49 -07:00
{
2019-03-21 02:43:52 +01:00
return ToStringFromDeserialization ;
2016-07-29 13:02:49 -07:00
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return PSObject . ToString ( null , this , null , null , null , true , false );
2016-03-30 14:20:52 -07:00
}
/// <summary>
/// Returns the string representation for this object. A ToString
/// CodeMethod or ScriptMethod will be used, if available. Enumerations items are
/// concatenated using $ofs.
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="format">Repassed to baseObject's IFormattable if present.</param>
/// <param name="formatProvider">Repassed to baseObject's IFormattable if present.</param>
2018-12-25 21:43:03 +05:00
/// <returns>The string representation for baseObject.</returns>
2018-12-29 08:25:49 +05:00
/// <exception cref="ExtendedTypeSystemException">If an exception was thrown by the BaseObject's ToString.</exception>
2016-07-29 13:02:49 -07:00
public string ToString ( string format , IFormatProvider formatProvider )
2016-03-30 14:20:52 -07:00
{
2019-01-06 06:51:20 +05:00
// If ToString value from deserialization is available,
// simply return it.
2019-03-21 02:43:52 +01:00
if ( ToStringFromDeserialization != null )
2016-07-29 13:02:49 -07:00
{
2019-03-21 02:43:52 +01:00
return ToStringFromDeserialization ;
2016-07-29 13:02:49 -07:00
}
2018-12-23 22:20:06 -08:00
2016-07-29 13:02:49 -07:00
return PSObject . ToString ( null , this , null , format , formatProvider , true , false );
2016-03-30 14:20:52 -07:00
}
private string PrivateToString ()
{
string result ;
try
{
2016-07-29 13:02:49 -07:00
result = this . ToString ();
2016-03-30 14:20:52 -07:00
}
2016-07-29 13:02:49 -07:00
catch ( ExtendedTypeSystemException )
2016-03-30 14:20:52 -07:00
{
result = this . BaseObject . GetType (). FullName ;
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return result ;
}
#endregion ToString
#region Clone
/// <summary>
/// Returns a copy of this PSObject. This will copy the BaseObject if
2017-01-16 13:31:14 -08:00
/// it is a value type, and use BaseObject.Clone() for the new PSObject,
2016-03-30 14:20:52 -07:00
/// if the BaseObject is ICloneable.
/// </summary>
2018-12-25 21:43:03 +05:00
/// <returns>A copy of this object.</returns>
2016-03-30 14:20:52 -07:00
public virtual PSObject Copy ()
{
PSObject returnValue = ( PSObject ) this . MemberwiseClone ();
if ( this . BaseObject is PSCustomObject )
{
2016-07-29 13:02:49 -07:00
returnValue . _immediateBaseObject = PSCustomObject . SelfInstance ;
2019-03-21 02:43:52 +01:00
returnValue . ImmediateBaseObjectIsEmpty = true ;
2016-03-30 14:20:52 -07:00
}
else
{
2016-07-29 13:02:49 -07:00
returnValue . _immediateBaseObject = _immediateBaseObject ;
2019-03-21 02:43:52 +01:00
returnValue . ImmediateBaseObjectIsEmpty = false ;
2016-03-30 14:20:52 -07:00
}
// Instance members will be recovered as necessary through the resurrection table.
returnValue . _instanceMembers = null ;
// The typename is not resurrected. A common reason to copy a PSObject is to change the TypeName,
// especially on a PSCustomObject - e.g. to a help object where we want to force a different view.
returnValue . _typeNames = null ;
2016-07-29 13:02:49 -07:00
returnValue . _members = new PSMemberInfoIntegratingCollection < PSMemberInfo >( returnValue , s_memberCollection );
returnValue . _properties = new PSMemberInfoIntegratingCollection < PSPropertyInfo >( returnValue , s_propertyCollection );
returnValue . _methods = new PSMemberInfoIntegratingCollection < PSMethodInfo >( returnValue , s_methodCollection );
2016-03-30 14:20:52 -07:00
2016-07-29 13:02:49 -07:00
returnValue . _adapterSet = GetMappedAdapter ( returnValue . _immediateBaseObject , returnValue . GetTypeTable ());
2016-03-30 14:20:52 -07:00
2018-09-25 21:27:43 -07:00
if ( returnValue . _immediateBaseObject is ICloneable cloneableBase )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
returnValue . _immediateBaseObject = cloneableBase . Clone ();
2016-03-30 14:20:52 -07:00
}
2016-07-29 13:02:49 -07:00
if ( returnValue . _immediateBaseObject is ValueType )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
returnValue . _immediateBaseObject = CopyValueType ( returnValue . _immediateBaseObject );
2016-03-30 14:20:52 -07:00
}
// needToReAddInstanceMembersAndTypeNames = returnValue will have a different key (different from "this") returned from GetKeyForResurrectionTables
bool needToReAddInstanceMembersAndTypeNames = ! object . ReferenceEquals ( GetKeyForResurrectionTables ( this ), GetKeyForResurrectionTables ( returnValue ));
if ( needToReAddInstanceMembersAndTypeNames )
{
Diagnostics . Assert (! returnValue . InstanceMembers . Any (), "needToReAddInstanceMembersAndTypeNames should mean that the new object has a fresh/empty list of instance members" );
foreach ( PSMemberInfo member in this . InstanceMembers )
{
if ( member . IsHidden )
{
continue ;
}
// Add will clone the member
returnValue . Members . Add ( member );
}
returnValue . TypeNames . Clear ();
foreach ( string typeName in this . InternalTypeNames )
{
returnValue . TypeNames . Add ( typeName );
}
}
2019-03-21 02:43:52 +01:00
returnValue . WriteStream = WriteStream ;
returnValue . HasGeneratedReservedMembers = false ;
2016-03-30 14:20:52 -07:00
return returnValue ;
}
internal static object CopyValueType ( object obj )
{
// this will force boxing and unboxing in a new object that will cause
// the copy of the value type
var newBaseArray = Array . CreateInstance ( obj . GetType (), 1 );
newBaseArray . SetValue ( obj , 0 );
return newBaseArray . GetValue ( 0 );
}
#endregion Clone
#region IComparable
/// <summary>
/// Compares the current instance with another object of the same type.
/// </summary>
/// <param name="obj">An object to compare with this instance.</param>
/// <returns>A 32-bit signed integer that indicates the relative order of the comparands.
/// The return value has these meanings:
/// Value Meaning
/// Less than zero This instance is less than obj.
/// Zero This instance is equal to obj.
/// Greater than zero This instance is greater than obj.
/// </returns>
/// <exception cref="ExtendedTypeSystemException"> If <paramref name="obj"/> has a different type
2016-08-28 05:44:55 +00:00
/// than this instance's BaseObject or if the BaseObject does not implement IComparable.
2016-03-30 14:20:52 -07:00
/// </exception>
public int CompareTo ( object obj )
{
2017-01-16 13:31:14 -08:00
// This ReferenceEquals is not just an optimization.
// It is necessary so that mshObject.Equals(mshObject) returns 0.
2016-03-30 14:20:52 -07:00
// Please see the comments inside the Equals implementation.
2019-11-06 08:47:32 +05:00
if ( object . ReferenceEquals ( this , obj ))
2016-03-30 14:20:52 -07:00
{
return 0 ;
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
try
{
// PSObject.Base instead of BaseObject could cause an infinite
// loop with LP.Compare calling this Compare.
return LanguagePrimitives . Compare ( this . BaseObject , obj );
}
catch ( ArgumentException e )
{
throw new ExtendedTypeSystemException ( "PSObjectCompareTo" , e ,
ExtendedTypeSystem . NotTheSameTypeOrNotIcomparable , this . PrivateToString (), PSObject . AsPSObject ( obj ). ToString (), "IComparable" );
}
}
#endregion IComparable
#region Equals and GetHashCode
/// <summary>
/// Determines whether the specified Object is equal to the current Object.
/// </summary>
/// <param name="obj">The Object to compare with the current Object.</param>
2018-12-25 21:43:03 +05:00
/// <returns>True if the specified Object is equal to the current Object; otherwise, false.</returns>
2016-03-30 14:20:52 -07:00
public override bool Equals ( object obj )
{
2017-01-16 13:31:14 -08:00
// There is a slight difference between BaseObject and PSObject.Base.
2016-03-30 14:20:52 -07:00
// PSObject.Base returns the containing PSObject that wraps an MshCustomBaseObject.
// BaseObject returns the MshCustomBaseObject.
// Because we have to call BaseObject here, and LP.Compare uses PSObject.Base
// we need the reference equals below so that mshObject.Equals(mshObject) returns true.
2019-11-06 08:47:32 +05:00
if ( object . ReferenceEquals ( this , obj ))
2016-03-30 14:20:52 -07:00
{
return true ;
}
// The above check validates if we are comparing with the same object references
2016-08-28 05:44:55 +00:00
// This check "shortcuts" the comparison if the first object is a CustomObject
2016-03-30 14:20:52 -07:00
// since 2 custom objects are not equal.
2019-11-06 08:47:32 +05:00
if ( object . ReferenceEquals ( this . BaseObject , PSCustomObject . SelfInstance ))
2016-03-30 14:20:52 -07:00
{
return false ;
}
// PSObject.Base instead of BaseObject could cause an infinite
// loop with LP.Equals calling this Equals.
return LanguagePrimitives . Equals ( this . BaseObject , obj );
}
/// <summary>
/// Serves as a hash function for a particular type, suitable for use in hashing algorithms and data structures like a hash table.
/// </summary>
2018-12-25 21:43:03 +05:00
/// <returns>A hash code for the current Object.</returns>
2016-03-30 14:20:52 -07:00
public override int GetHashCode ()
{
return this . BaseObject . GetHashCode ();
}
#endregion Equals and GetHashCode
internal void AddOrSetProperty ( string memberName , object value )
{
2018-09-25 21:27:43 -07:00
if ( PSGetMemberBinder . TryGetInstanceMember ( this , memberName , out PSMemberInfo memberInfo ) && memberInfo is PSPropertyInfo )
2016-03-30 14:20:52 -07:00
{
memberInfo . Value = value ;
}
else
{
Properties . Add ( new PSNoteProperty ( memberName , value ));
}
}
internal void AddOrSetProperty ( PSNoteProperty property )
{
2018-09-25 21:27:43 -07:00
if ( PSGetMemberBinder . TryGetInstanceMember ( this , property . Name , out PSMemberInfo memberInfo ) && memberInfo is PSPropertyInfo )
2016-03-30 14:20:52 -07:00
{
memberInfo . Value = property . Value ;
}
else
{
Properties . Add ( property );
}
}
#endregion instance methods
#region public const strings
/// <summary>
2019-01-06 04:40:24 +05:00
/// The name of the member set for adapted members.
2016-03-30 14:20:52 -07:00
/// </summary>
/// <remarks>
2016-08-28 05:44:55 +00:00
/// This needs to be Lower cased as it saves some comparison time elsewhere.
2016-03-30 14:20:52 -07:00
/// </remarks>
public const string AdaptedMemberSetName = "psadapted" ;
/// <summary>
2019-01-06 04:40:24 +05:00
/// The name of the member set for extended members.
2016-03-30 14:20:52 -07:00
/// </summary>
/// <remarks>
2016-08-28 05:44:55 +00:00
/// This needs to be Lower cased as it saves some comparison time elsewhere.
2016-03-30 14:20:52 -07:00
/// </remarks>
public const string ExtendedMemberSetName = "psextended" ;
/// <summary>
2019-01-06 04:40:24 +05:00
/// The name of the member set for the BaseObject's members.
2016-03-30 14:20:52 -07:00
/// </summary>
/// <remarks>
2016-08-28 05:44:55 +00:00
/// This needs to be Lower cased as it saves some comparison time elsewhere.
2016-03-30 14:20:52 -07:00
/// </remarks>
public const string BaseObjectMemberSetName = "psbase" ;
/// <summary>
2019-01-06 04:40:24 +05:00
/// The PSObject's properties.
2016-03-30 14:20:52 -07:00
/// </summary>
/// <remarks>
2016-08-28 05:44:55 +00:00
/// This needs to be Lower cased as it saves some comparison time elsewhere.
2016-03-30 14:20:52 -07:00
/// </remarks>
internal const string PSObjectMemberSetName = "psobject" ;
/// <summary>
2019-01-10 02:07:41 +05:00
/// A shortcut to .PSObject.TypeNames.
2016-03-30 14:20:52 -07:00
/// </summary>
/// <remarks>
2016-08-28 05:44:55 +00:00
/// This needs to be Lower cased as it saves some comparison time elsewhere.
2016-03-30 14:20:52 -07:00
/// </remarks>
internal const string PSTypeNames = "pstypenames" ;
#endregion public const strings
2016-07-29 13:02:49 -07:00
2016-03-30 14:20:52 -07:00
#region serialization
/// <summary>
2019-01-06 04:40:24 +05:00
/// Implements the ISerializable contract for serializing a PSObject.
2016-03-30 14:20:52 -07:00
/// </summary>
2018-12-28 16:39:06 +05:00
/// <param name="info">Serialization information for this instance.</param>
/// <param name="context">The streaming context for this instance.</param>
2016-03-30 14:20:52 -07:00
public virtual void GetObjectData ( SerializationInfo info , StreamingContext context )
{
if ( info == null )
{
throw PSTraceSource . NewArgumentNullException ( "info" );
}
// We create a wrapper PSObject, so that we can successfully deserialize it
2018-09-25 21:27:43 -07:00
string serializedContent ;
2019-03-21 02:43:52 +01:00
if ( this . ImmediateBaseObjectIsEmpty )
2016-03-30 14:20:52 -07:00
{
PSObject serializeTarget = new PSObject ( this );
serializedContent = PSSerializer . Serialize ( serializeTarget );
}
else
{
serializedContent = PSSerializer . Serialize ( this );
}
info . AddValue ( "CliXml" , serializedContent );
}
/// <summary>
/// </summary>
/// <param name="settings"></param>
/// <param name="noteName"></param>
/// <param name="defaultValue"></param>
/// <param name="expectedType"></param>
/// <param name="shouldReplicateInstance">
/// true to make this PSObject as the owner of the memberset.
/// </param>
/// <param name="ownerObject">
2016-08-28 05:44:55 +00:00
/// PSObject to be used while replicating the owner for PSMemberSet
2016-03-30 14:20:52 -07:00
/// </param>
/// <returns></returns>
2016-07-29 13:02:49 -07:00
internal static object GetNoteSettingValue ( PSMemberSet settings , string noteName ,
object defaultValue , Type expectedType ,
2016-03-30 14:20:52 -07:00
bool shouldReplicateInstance , PSObject ownerObject )
{
if ( settings == null )
{
return defaultValue ;
}
if ( shouldReplicateInstance )
{
settings . ReplicateInstance ( ownerObject );
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
PSNoteProperty note = settings . Members [ noteName ] as PSNoteProperty ;
if ( note == null )
{
return defaultValue ;
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
object noteValue = note . Value ;
if ( noteValue == null || noteValue . GetType () != expectedType )
{
return defaultValue ;
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return note . Value ;
}
internal int GetSerializationDepth ( TypeTable backupTypeTable )
{
int result = 0 ;
TypeTable typeTable = backupTypeTable ?? this . GetTypeTable ();
2018-06-26 02:37:09 +05:00
if ( typeTable != null )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
PSMemberSet standardMemberSet = TypeTableGetMemberDelegate < PSMemberSet >( this ,
2016-03-30 14:20:52 -07:00
typeTable , TypeTable . PSStandardMembers );
result = ( int ) GetNoteSettingValue ( standardMemberSet , TypeTable . SerializationDepth , 0 , typeof ( int ), true , this );
}
return result ;
}
/// <summary>
/// </summary>
/// <param name="backupTypeTable">
/// TypeTable to use if this PSObject.GetTypeTable() returns null. This will happen
/// in the remoting scenario on the client/server side (where a LocalRunspace may not be
/// present).
/// </param>
/// <returns></returns>
internal PSPropertyInfo GetStringSerializationSource ( TypeTable backupTypeTable )
{
PSMemberInfo result = this . GetPSStandardMember ( backupTypeTable , TypeTable . StringSerializationSource );
return result as PSPropertyInfo ;
}
/// <summary>
/// </summary>
/// <param name="backupTypeTable">
/// TypeTable to use if this PSObject.GetTypeTable() returns null. This will happen
/// in the remoting scenario on the client/server side (where a LocalRunspace may not be
/// present).
/// </param>
/// <returns></returns>
internal SerializationMethod GetSerializationMethod ( TypeTable backupTypeTable )
{
2019-11-08 00:49:06 +05:00
SerializationMethod result = TypeTable . DefaultSerializationMethod ;
2016-03-30 14:20:52 -07:00
2016-08-02 22:25:13 -07:00
TypeTable typeTable = backupTypeTable ?? this . GetTypeTable ();
2018-06-26 02:37:09 +05:00
if ( typeTable != null )
2016-03-30 14:20:52 -07:00
{
2016-07-29 13:02:49 -07:00
PSMemberSet standardMemberSet = TypeTableGetMemberDelegate < PSMemberSet >( this ,
2016-03-30 14:20:52 -07:00
typeTable , TypeTable . PSStandardMembers );
result = ( SerializationMethod ) GetNoteSettingValue ( standardMemberSet ,
2019-11-08 00:49:06 +05:00
TypeTable . SerializationMethodNode , TypeTable . DefaultSerializationMethod , typeof ( SerializationMethod ), true , this );
2016-03-30 14:20:52 -07:00
}
return result ;
}
internal PSMemberSet PSStandardMembers
{
get
{
2018-09-25 21:27:43 -07:00
var retVal = TypeTableGetMemberDelegate < PSMemberSet >( this , TypeTable . PSStandardMembers );
2016-03-30 14:20:52 -07:00
if ( retVal != null )
{
2016-07-29 13:02:49 -07:00
retVal = ( PSMemberSet ) retVal . Copy ();
2016-03-30 14:20:52 -07:00
retVal . ReplicateInstance ( this );
return retVal ;
}
retVal = this . InstanceMembers [ TypeTable . PSStandardMembers ] as PSMemberSet ;
return retVal ;
}
}
internal PSMemberInfo GetPSStandardMember ( TypeTable backupTypeTable , string memberName )
{
PSMemberInfo result = null ;
2016-08-02 22:25:13 -07:00
TypeTable typeTable = backupTypeTable ?? this . GetTypeTable ();
2016-03-30 14:20:52 -07:00
if ( typeTable != null )
{
PSMemberSet standardMemberSet = TypeTableGetMemberDelegate < PSMemberSet >(
this , typeTable , TypeTable . PSStandardMembers );
2018-06-26 02:37:09 +05:00
if ( standardMemberSet != null )
2016-03-30 14:20:52 -07:00
{
standardMemberSet . ReplicateInstance ( this );
2016-07-29 13:02:49 -07:00
PSMemberInfoIntegratingCollection < PSMemberInfo > members =
2016-03-30 14:20:52 -07:00
new PSMemberInfoIntegratingCollection < PSMemberInfo >(
2016-07-29 13:02:49 -07:00
standardMemberSet ,
2016-03-30 14:20:52 -07:00
GetMemberCollection ( PSMemberViewTypes . All , backupTypeTable ));
result = members [ memberName ];
}
}
2016-08-02 22:25:13 -07:00
return result ?? InstanceMembers [ TypeTable . PSStandardMembers ] as PSMemberSet ;
2016-03-30 14:20:52 -07:00
}
/// <summary>
/// Used by Deserializer to deserialize a serialized object to a given type
/// (as specified in the a types.ps1xml file)
/// </summary>
/// <param name="backupTypeTable">
/// TypeTable to use if this PSObject.GetTypeTable() returns null. This will happen
/// in the remoting scenario on the client/server side (where a LocalRunspace may not be
/// present).
/// </param>
internal Type GetTargetTypeForDeserialization ( TypeTable backupTypeTable )
{
PSMemberInfo targetType = this . GetPSStandardMember ( backupTypeTable , TypeTable . TargetTypeForDeserialization );
2018-09-25 21:27:43 -07:00
return targetType ?. Value as Type ;
2016-03-30 14:20:52 -07:00
}
/// <summary>
2019-01-06 04:40:24 +05:00
/// This is only going to be called if SerializationMethod is SpecificProperties.
2016-03-30 14:20:52 -07:00
/// </summary>
/// <param name="backupTypeTable">
/// TypeTable to use if this PSObject.GetTypeTable() returns null. This will happen
/// in the remoting scenario on the client side (where a LocalRunspace may not be
/// present).
/// </param>
2018-12-25 21:43:03 +05:00
/// <returns>A collection with only the specific properties to serialize.</returns>
2016-03-30 14:20:52 -07:00
internal Collection < string > GetSpecificPropertiesToSerialize ( TypeTable backupTypeTable )
{
2016-08-02 22:25:13 -07:00
TypeTable typeTable = backupTypeTable ?? this . GetTypeTable ();
2018-06-26 02:37:09 +05:00
if ( typeTable != null )
2016-03-30 14:20:52 -07:00
{
Collection < string > tmp = typeTable . GetSpecificProperties ( this . InternalTypeNames );
return tmp ;
}
return new Collection < string >( new List < string >());
}
2016-07-29 13:02:49 -07:00
internal bool ShouldSerializeAdapter ()
2016-03-30 14:20:52 -07:00
{
2019-03-21 02:43:52 +01:00
if ( this . IsDeserialized )
2016-03-30 14:20:52 -07:00
{
2019-03-21 02:43:52 +01:00
return this . AdaptedMembers != null ;
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2019-03-21 02:43:52 +01:00
return ! this . ImmediateBaseObjectIsEmpty ;
2016-03-30 14:20:52 -07:00
}
2016-07-29 13:02:49 -07:00
internal PSMemberInfoInternalCollection < PSPropertyInfo > GetAdaptedProperties ()
2016-03-30 14:20:52 -07:00
{
2019-03-21 02:43:52 +01:00
return GetProperties ( this . AdaptedMembers , this . InternalAdapter );
2016-03-30 14:20:52 -07:00
}
2016-07-29 13:02:49 -07:00
private PSMemberInfoInternalCollection < PSPropertyInfo > GetProperties ( PSMemberInfoInternalCollection < PSPropertyInfo > serializedMembers , Adapter particularAdapter )
2016-03-30 14:20:52 -07:00
{
2019-03-21 02:43:52 +01:00
if ( this . IsDeserialized )
2016-03-30 14:20:52 -07:00
{
return serializedMembers ;
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
PSMemberInfoInternalCollection < PSPropertyInfo > returnValue = new PSMemberInfoInternalCollection < PSPropertyInfo >();
2016-07-29 13:02:49 -07:00
foreach ( PSPropertyInfo member in particularAdapter . BaseGetMembers < PSPropertyInfo >( _immediateBaseObject ))
2016-03-30 14:20:52 -07:00
{
returnValue . Add ( member );
}
return returnValue ;
}
internal static void CopyDeserializerFields ( PSObject source , PSObject target )
{
2019-03-21 02:43:52 +01:00
if (! target . IsDeserialized )
2016-03-30 14:20:52 -07:00
{
2019-03-21 02:43:52 +01:00
target . IsDeserialized = source . IsDeserialized ;
target . AdaptedMembers = source . AdaptedMembers ;
target . ClrMembers = source . ClrMembers ;
2016-03-30 14:20:52 -07:00
}
2019-03-21 02:43:52 +01:00
if ( target . ToStringFromDeserialization == null )
2016-03-30 14:20:52 -07:00
{
2019-03-21 02:43:52 +01:00
target . ToStringFromDeserialization = source . ToStringFromDeserialization ;
2016-03-30 14:20:52 -07:00
target . TokenText = source . TokenText ;
}
}
/// <summary>
2019-01-06 04:40:24 +05:00
/// Set base object.
2016-03-30 14:20:52 -07:00
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="value">Object which is set as core.</param>
2018-12-28 16:39:06 +05:00
/// <param name="overrideTypeInfo">If true, overwrite the type information.</param>
2016-03-30 14:20:52 -07:00
///<remarks>This method is to be used only by Serialization code</remarks>
internal void SetCoreOnDeserialization ( object value , bool overrideTypeInfo )
{
2019-03-21 02:43:52 +01:00
Diagnostics . Assert ( this . ImmediateBaseObjectIsEmpty , "BaseObject should be PSCustomObject for deserialized objects" );
2016-03-30 14:20:52 -07:00
Diagnostics . Assert ( value != null , "known objects are never null" );
2019-03-21 02:43:52 +01:00
this . ImmediateBaseObjectIsEmpty = false ;
2016-07-29 13:02:49 -07:00
_immediateBaseObject = value ;
_adapterSet = GetMappedAdapter ( _immediateBaseObject , GetTypeTable ());
2016-03-30 14:20:52 -07:00
if ( overrideTypeInfo )
{
this . InternalTypeNames = this . InternalAdapter . BaseGetTypeNameHierarchy ( value );
}
}
#endregion serialization
/// <summary>
/// This class is solely used by PSObject to support .net member lookup for all the
/// adapters except for dotNetInstanceAdapter, mshMemberSetAdapter and mshObjectAdapter.
/// If the original adapter is not one of those, then .net members are also exposed
/// on the PSObject. This will have the following effect:
2017-01-16 13:31:14 -08:00
///
2016-03-30 14:20:52 -07:00
/// 1. Every adapted object like xml, wmi, adsi will show adapted members as well as
/// .net members.
/// 2. Users will not need to access PSBase to access original .net members.
/// 3. This will fix v1.0 ADSI adapter where most of the complaints were about
/// discovering original .net members.
2017-01-16 13:31:14 -08:00
///
2016-08-28 05:44:55 +00:00
/// Use of this class will allow us to customize the ultimate .net member lookup.
2017-01-16 13:31:14 -08:00
/// For example, XML adapter already exposes .net methods.
2016-03-30 14:20:52 -07:00
/// Using this class you can choose exact .net adapter to support .net
/// member lookup and avoid lookup duplication.
/// </summary>
/// <remarks>
/// This class is intended for internal use only.
/// </remarks>
internal class AdapterSet
{
#region Private Data
2016-08-28 05:44:55 +00:00
// original adapter like Xml, ManagementClass, DirectoryEntry etc.
2016-03-30 14:20:52 -07:00
// .net adapter
#endregion
#region Properties
/// <summary>
/// This property can be accessed only internally and hence
/// no checks are performed on input.
/// </summary>
2016-08-02 13:29:09 -07:00
internal Adapter OriginalAdapter { get ; set ; }
2016-03-30 14:20:52 -07:00
2016-08-02 13:29:09 -07:00
internal DotNetAdapter DotNetAdapter { get ; }
2016-03-30 14:20:52 -07:00
#endregion
#region Constructors
internal AdapterSet ( Adapter adapter , DotNetAdapter dotnetAdapter )
{
2016-08-02 13:29:09 -07:00
OriginalAdapter = adapter ;
DotNetAdapter = dotnetAdapter ;
2016-03-30 14:20:52 -07:00
}
#endregion
}
#region Dynamic metaobject implementation
internal class PSDynamicMetaObject : DynamicMetaObject
{
internal PSDynamicMetaObject ( Expression expression , PSObject value )
: base ( expression , BindingRestrictions . Empty , value )
{
}
2018-09-25 21:27:43 -07:00
private new PSObject Value => ( PSObject ) base . Value ;
2016-03-30 14:20:52 -07:00
private DynamicMetaObject GetUnwrappedObject ()
{
return new DynamicMetaObject ( Expression . Call ( CachedReflectionInfo . PSObject_Base , this . Expression ), this . Restrictions , PSObject . Base ( Value ));
}
public override IEnumerable < string > GetDynamicMemberNames ()
{
return ( from member in Value . Members select member . Name );
}
private bool MustDeferIDMOP ()
{
var baseObject = PSObject . Base ( Value );
return baseObject is IDynamicMetaObjectProvider && !( baseObject is PSObject );
}
private DynamicMetaObject DeferForIDMOP ( DynamicMetaObjectBinder binder , params DynamicMetaObject [] args )
{
Diagnostics . Assert ( MustDeferIDMOP (), "Defer only works for idmop wrapped PSObjects" );
Expression [] exprs = new Expression [ args . Length + 1 ];
BindingRestrictions restrictions = this . Restrictions == BindingRestrictions . Empty ? this . PSGetTypeRestriction () : this . Restrictions ;
exprs [ 0 ] = Expression . Call ( CachedReflectionInfo . PSObject_Base , this . Expression . Cast ( typeof ( object )));
for ( int i = 0 ; i < args . Length ; i ++)
{
exprs [ i + 1 ] = args [ i ]. Expression ;
restrictions = restrictions . Merge ( args [ i ]. Restrictions == BindingRestrictions . Empty ? args [ i ]. PSGetTypeRestriction () : args [ i ]. Restrictions );
}
return new DynamicMetaObject ( DynamicExpression . Dynamic ( binder , binder . ReturnType , exprs ), restrictions );
}
public override DynamicMetaObject BindBinaryOperation ( BinaryOperationBinder binder , DynamicMetaObject arg )
{
if ( MustDeferIDMOP ())
{
return DeferForIDMOP ( binder , arg );
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return binder . FallbackBinaryOperation ( GetUnwrappedObject (), arg );
}
public override DynamicMetaObject BindConvert ( ConvertBinder binder )
{
if ( MustDeferIDMOP ())
{
return DeferForIDMOP ( binder );
}
// This will invoke the language binder, meaning we might not invoke PowerShell conversions. This
// is an interesting design choice, which, if revisited, needs some care because there are multiple
// binders that PowerShell uses for conversion, the normal one, and the one used when we want to
// attempt enumeration of some object that might or might not implement IEnumerable.
return binder . FallbackConvert ( this );
}
public override DynamicMetaObject BindDeleteIndex ( DeleteIndexBinder binder , DynamicMetaObject [] indexes )
{
if ( MustDeferIDMOP ())
{
return DeferForIDMOP ( binder , indexes );
}
return binder . FallbackDeleteIndex ( GetUnwrappedObject (), indexes );
}
public override DynamicMetaObject BindDeleteMember ( DeleteMemberBinder binder )
{
if ( MustDeferIDMOP ())
{
return DeferForIDMOP ( binder );
}
return binder . FallbackDeleteMember ( GetUnwrappedObject ());
}
public override DynamicMetaObject BindGetIndex ( GetIndexBinder binder , DynamicMetaObject [] indexes )
{
if ( MustDeferIDMOP ())
{
return DeferForIDMOP ( binder , indexes );
}
return binder . FallbackGetIndex ( GetUnwrappedObject (), indexes );
}
public override DynamicMetaObject BindInvoke ( InvokeBinder binder , DynamicMetaObject [] args )
{
if ( MustDeferIDMOP ())
{
return DeferForIDMOP ( binder , args );
}
return binder . FallbackInvoke ( GetUnwrappedObject (), args );
}
public override DynamicMetaObject BindSetIndex ( SetIndexBinder binder , DynamicMetaObject [] indexes , DynamicMetaObject value )
{
if ( MustDeferIDMOP ())
{
return DeferForIDMOP ( binder , indexes . Append ( value ). ToArray ());
}
return binder . FallbackSetIndex ( GetUnwrappedObject (), indexes , value );
}
public override DynamicMetaObject BindUnaryOperation ( UnaryOperationBinder binder )
{
if ( MustDeferIDMOP ())
{
return DeferForIDMOP ( binder );
}
return binder . FallbackUnaryOperation ( GetUnwrappedObject ());
}
public override DynamicMetaObject BindInvokeMember ( InvokeMemberBinder binder , DynamicMetaObject [] args )
{
if ( MustDeferIDMOP ())
{
return DeferForIDMOP ( binder , args );
}
return ( binder as PSInvokeMemberBinder ??
( InvokeMemberBinder )( binder as PSInvokeBaseCtorBinder ) ??
PSInvokeMemberBinder . Get ( binder . Name , binder . CallInfo , false , false , null , null )). FallbackInvokeMember ( this , args );
}
public override DynamicMetaObject BindGetMember ( GetMemberBinder binder )
{
if ( MustDeferIDMOP ())
{
return DeferForIDMOP ( binder );
}
return ( binder as PSGetMemberBinder ?? PSGetMemberBinder . Get ( binder . Name , ( Type ) null , false )). FallbackGetMember ( this );
}
public override DynamicMetaObject BindSetMember ( SetMemberBinder binder , DynamicMetaObject value )
{
if ( MustDeferIDMOP ())
{
return DeferForIDMOP ( binder , value );
}
return ( binder as PSSetMemberBinder ?? PSSetMemberBinder . Get ( binder . Name , ( Type ) null , false )). FallbackSetMember ( this , value );
}
}
DynamicMetaObject IDynamicMetaObjectProvider . GetMetaObject ( Expression parameter )
{
return new PSDynamicMetaObject ( parameter , this );
}
#endregion
2019-03-21 02:43:52 +01:00
internal bool IsDeserialized
{
get => _flags . HasFlag ( PSObjectFlags . IsDeserialized );
set
{
if ( value )
{
_flags |= PSObjectFlags . IsDeserialized ;
}
else
{
_flags &= ~ PSObjectFlags . IsDeserialized ;
}
}
}
private bool StoreTypeNameAndInstanceMembersLocally
{
get => _flags . HasFlag ( PSObjectFlags . StoreTypeNameAndInstanceMembersLocally );
set
{
if ( value )
{
_flags |= PSObjectFlags . StoreTypeNameAndInstanceMembersLocally ;
}
else
{
_flags &= ~ PSObjectFlags . StoreTypeNameAndInstanceMembersLocally ;
}
}
}
2016-03-30 14:20:52 -07:00
internal bool IsHelpObject
{
2019-03-21 02:43:52 +01:00
get => _flags . HasFlag ( PSObjectFlags . IsHelpObject );
set
{
if ( value )
{
_flags |= PSObjectFlags . IsHelpObject ;
}
else
{
_flags &= ~ PSObjectFlags . IsHelpObject ;
}
}
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2019-03-21 02:43:52 +01:00
internal bool HasGeneratedReservedMembers
{
get => _flags . HasFlag ( PSObjectFlags . HasGeneratedReservedMembers );
set
{
if ( value )
{
_flags |= PSObjectFlags . HasGeneratedReservedMembers ;
}
else
{
_flags &= ~ PSObjectFlags . HasGeneratedReservedMembers ;
}
}
}
2016-03-30 14:20:52 -07:00
2019-03-21 02:43:52 +01:00
internal bool ImmediateBaseObjectIsEmpty
{
get => _flags . HasFlag ( PSObjectFlags . ImmediateBaseObjectIsEmpty );
set
{
if ( value )
{
_flags |= PSObjectFlags . ImmediateBaseObjectIsEmpty ;
}
else
{
_flags &= ~ PSObjectFlags . ImmediateBaseObjectIsEmpty ;
}
}
}
/// <summary>
/// If 'this' is non-null, return this string as the ToString() for this wrapped object.
/// </summary>
internal string TokenText { get ; set ; }
/// <summary>
/// Sets the 'ToString' value on deserialization.
/// </summary>
internal string ToStringFromDeserialization { get ; set ; }
/// <summary>
/// This property contains a stream type used by the formatting system.
/// </summary>
internal WriteStreamType WriteStream { get ; set ; }
/// <summary>
/// Members from the adapter of the object before it was serialized
/// Null for live objects but not null for deserialized objects.
/// </summary>
internal PSMemberInfoInternalCollection < PSPropertyInfo > AdaptedMembers { get ; set ; }
internal static DotNetAdapter DotNetStaticAdapter => s_dotNetStaticAdapter ;
internal static PSTraceSource MemberResolution => s_memberResolution ;
/// <summary>
/// Members from the adapter of the object before it was serialized
/// Null for live objects but not null for deserialized objects.
/// </summary>
internal PSMemberInfoInternalCollection < PSPropertyInfo > ClrMembers { get ; set ; }
internal static DotNetAdapter DotNetInstanceAdapter => s_dotNetInstanceAdapter ;
/// <summary>
/// Gets an instance member if it's name matches the predicate. Otherwise null.
/// </summary>
internal PSPropertyInfo GetFirstPropertyOrDefault ( MemberNamePredicate predicate )
{
return Properties . FirstOrDefault ( predicate );
}
[Flags]
private enum PSObjectFlags : byte
{
None = 0 ,
/// <summary>
/// This flag is set in deserialized shellobject.
/// </summary>
IsDeserialized = 0 b00000001 ,
/// <summary>
/// Set to true when the BaseObject is PSCustomObject.
/// </summary>
HasGeneratedReservedMembers = 0 b00000010 ,
ImmediateBaseObjectIsEmpty = 0 b00000100 ,
IsHelpObject = 0 b00001000 ,
/// <summary>
/// Indicate whether we store the instance members and type names locally
/// for this PSObject instance.
/// </summary>
StoreTypeNameAndInstanceMembersLocally = 0 b00010000 ,
}
}
/// <summary>
/// Specifies special stream write processing.
/// </summary>
internal enum WriteStreamType : byte
{
None ,
Output ,
Error ,
Warning ,
Verbose ,
Debug ,
Information
2016-03-30 14:20:52 -07:00
}
/// <summary>
2017-01-16 13:31:14 -08:00
/// Serves as a placeholder BaseObject when PSObject's
2016-03-30 14:20:52 -07:00
/// constructor with no parameters is used.
/// </summary>
public class PSCustomObject
{
/// <summary>
2019-01-06 04:40:24 +05:00
/// To prevent other instances than SelfInstance.
2016-03-30 14:20:52 -07:00
/// </summary>
private PSCustomObject () { }
internal static PSCustomObject SelfInstance = new PSCustomObject ();
/// <summary>
2019-01-06 04:40:24 +05:00
/// Returns an empty string.
2016-03-30 14:20:52 -07:00
/// </summary>
public override string ToString ()
{
2018-06-13 00:30:10 +05:00
return string . Empty ;
2016-03-30 14:20:52 -07:00
}
}
/// <summary>
/// </summary>
/// <remarks>
/// Please keep in sync with SerializationMethod from
/// C:\e\win7_powershell\admin\monad\nttargets\assemblies\logging\ETW\Manifests\Microsoft-Windows-PowerShell-Instrumentation.man
/// </remarks>
internal enum SerializationMethod
{
AllPublicProperties = 0 ,
String = 1 ,
SpecificProperties = 2
2019-03-21 02:43:52 +01:00
}
2016-03-30 14:20:52 -07:00
}
#pragma warning restore 56500
namespace Microsoft.PowerShell
{
/// <summary>
2019-01-06 04:40:24 +05:00
/// Contains auxiliary ToString CodeMethod implementations for some types.
2016-03-30 14:20:52 -07:00
/// </summary>
public static partial class ToStringCodeMethods
{
private static void AddGenericArguments ( StringBuilder sb , Type [] genericArguments , bool dropNamespaces )
{
sb . Append ( '[' );
for ( int i = 0 ; i < genericArguments . Length ; i ++)
{
if ( i > 0 ) { sb . Append ( ',' ); }
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
sb . Append ( Type ( genericArguments [ i ], dropNamespaces ));
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
sb . Append ( ']' );
}
2016-12-21 15:33:05 -08:00
internal static string Type ( Type type , bool dropNamespaces = false , string key = null )
2016-03-30 14:20:52 -07:00
{
if ( type == null )
2019-03-23 09:52:30 +05:00
{
2018-09-25 21:27:43 -07:00
return string . Empty ;
2019-03-23 09:52:30 +05:00
}
2016-03-30 14:20:52 -07:00
string result ;
2018-04-13 15:10:10 -07:00
if ( type . IsGenericType && ! type . IsGenericTypeDefinition )
2016-03-30 14:20:52 -07:00
{
string genericDefinition = Type ( type . GetGenericTypeDefinition (), dropNamespaces );
// For regular generic types, we find the backtick character, for example:
2017-01-16 13:31:14 -08:00
// System.Collections.Generic.List`1[T] ->
2016-03-30 14:20:52 -07:00
// System.Collections.Generic.List[string]
// For nested generic types, we find the left bracket character, for example:
// System.Collections.Generic.Dictionary`2+Enumerator[TKey, TValue] ->
// System.Collections.Generic.Dictionary`2+Enumerator[string,string]
2018-04-13 15:10:10 -07:00
int backtickOrLeftBracketIndex = genericDefinition . LastIndexOf ( type . IsNested ? '[' : '`' );
2016-03-30 14:20:52 -07:00
var sb = new StringBuilder ( genericDefinition , 0 , backtickOrLeftBracketIndex , 512 );
AddGenericArguments ( sb , type . GetGenericArguments (), dropNamespaces );
result = sb . ToString ();
}
2018-04-13 15:10:10 -07:00
else if ( type . IsArray )
2016-03-30 14:20:52 -07:00
{
string elementDefinition = Type ( type . GetElementType (), dropNamespaces );
var sb = new StringBuilder ( elementDefinition , elementDefinition . Length + 10 );
sb . Append ( "[" );
for ( int i = 0 ; i < type . GetArrayRank () - 1 ; ++ i )
{
sb . Append ( "," );
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
sb . Append ( "]" );
result = sb . ToString ();
}
else
{
2016-12-21 15:33:05 -08:00
result = TypeAccelerators . FindBuiltinAccelerator ( type , key );
2016-03-30 14:20:52 -07:00
if ( result == null )
{
2016-12-21 15:33:05 -08:00
if ( type == typeof ( PSCustomObject ))
{
return type . Name ;
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
if ( dropNamespaces )
{
2018-04-13 15:10:10 -07:00
if ( type . IsNested )
2016-03-30 14:20:52 -07:00
{
2016-08-28 05:44:55 +00:00
// For nested types, we should return OuterType+InnerType. For example,
2016-03-30 14:20:52 -07:00
// System.Environment+SpecialFolder -> Environment+SpecialFolder
string fullName = type . ToString ();
result = type . Namespace == null
? fullName
: fullName . Substring ( type . Namespace . Length + 1 );
}
else
{
result = type . Name ;
}
}
else
{
result = type . ToString ();
}
}
}
// We can't round trip anything with a generic parameter.
// We also can't round trip if we're dropping the namespace.
2018-04-13 15:10:10 -07:00
if (! type . IsGenericParameter
&& ! type . ContainsGenericParameters
2016-03-30 14:20:52 -07:00
&& ! dropNamespaces
2018-04-13 15:10:10 -07:00
&& ! type . Assembly . GetCustomAttributes ( typeof ( DynamicClassImplementationAssemblyAttribute )). Any ())
2016-03-30 14:20:52 -07:00
{
2018-09-25 21:27:43 -07:00
TypeResolver . TryResolveType ( result , out Type roundTripType );
2016-03-30 14:20:52 -07:00
if ( roundTripType != type )
{
result = type . AssemblyQualifiedName ;
}
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return result ;
}
/// <summary>
2019-01-06 04:40:24 +05:00
/// ToString implementation for Type.
2016-03-30 14:20:52 -07:00
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="instance">Instance of PSObject wrapping a Type.</param>
2016-03-30 14:20:52 -07:00
public static string Type ( PSObject instance )
{
if ( instance == null )
2018-09-25 21:27:43 -07:00
{
return string . Empty ;
}
2016-03-30 14:20:52 -07:00
return Type (( Type ) instance . BaseObject );
}
/// <summary>
2019-01-06 04:40:24 +05:00
/// ToString implementation for XmlNode.
2016-03-30 14:20:52 -07:00
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="instance">Instance of PSObject wrapping an XmlNode.</param>
2016-03-30 14:20:52 -07:00
public static string XmlNode ( PSObject instance )
{
2018-09-25 21:27:43 -07:00
XmlNode node = ( XmlNode ) instance ?. BaseObject ;
2016-03-30 14:20:52 -07:00
if ( node == null )
2018-09-25 21:27:43 -07:00
{
return string . Empty ;
}
2016-03-30 14:20:52 -07:00
return node . LocalName ;
}
/// <summary>
2019-01-06 04:40:24 +05:00
/// ToString implementation for XmlNodeList.
2016-03-30 14:20:52 -07:00
/// </summary>
2018-12-29 08:25:49 +05:00
/// <param name="instance">Instance of PSObject wrapping an XmlNodeList.</param>
2016-03-30 14:20:52 -07:00
public static string XmlNodeList ( PSObject instance )
{
2018-09-25 21:27:43 -07:00
XmlNodeList nodes = ( XmlNodeList ) instance ?. BaseObject ;
2016-03-30 14:20:52 -07:00
if ( nodes == null )
2018-09-25 21:27:43 -07:00
{
return string . Empty ;
2018-12-25 21:43:03 +05:00
}
2018-09-25 21:27:43 -07:00
2016-03-30 14:20:52 -07:00
if ( nodes . Count == 1 )
{
if ( nodes [ 0 ] == null )
{
2018-09-25 21:27:43 -07:00
return string . Empty ;
2016-03-30 14:20:52 -07:00
}
2018-12-23 22:20:06 -08:00
2016-03-30 14:20:52 -07:00
return PSObject . AsPSObject ( nodes [ 0 ]). ToString ();
}
2018-09-25 21:27:43 -07:00
return PSObject . ToStringEnumerable ( context : null , enumerable : nodes , separator : null , format : null , formatProvider : null );
2016-03-30 14:20:52 -07:00
}
}
}