2016-03-30 14:20:52 -07:00
/********************************************************************++
Copyright (c) Microsoft Corporation. All rights reserved.
--********************************************************************/
using System.Collections ;
using System.Collections.Generic ;
using System.Collections.Specialized ;
using System.ComponentModel ;
using System.Data ;
using System.Globalization ;
using System.Linq ;
using System.Linq.Expressions ;
using System.Management.Automation.Language ;
using System.Reflection ;
using System.Runtime.CompilerServices ;
using System.Text.RegularExpressions ;
using System.Xml ;
using System.IO ;
using System.Text ;
using System.Management.Automation.Internal ;
using System.Management.Automation.Runspaces ;
using System.Diagnostics.CodeAnalysis ; // for fxcop
using Dbg = System . Management . Automation . Diagnostics ;
using System.Reflection.Emit ;
#if ! CORECLR
// System.DirectoryServices are not in CoreCLR
using System.DirectoryServices ;
#endif
#pragma warning disable 1634 , 1691 // Stops compiler from warning about unknown warnings
#pragma warning disable 56500
namespace System.Management.Automation
{
#region public type converters
/// <summary>
/// Defines a base class implemented when you need to customize the type conversion for a target class.
/// </summary>
/// <remarks>
/// There are two ways of associating the PSTypeConverter with its target class:
/// - Through the type configuration file.
/// - By applying a TypeConverterAttribute to the target class.
///
/// Unlike System.ComponentModel.TypeConverter, PSTypeConverter can be applied to a family of types (like all types derived from System.Enum).
/// PSTypeConverter has two main differences from TypeConverter:
/// - It can be applied to a family of types and not only the one type as in TypeConverter. In order to do that
/// ConvertFrom and CanConvertFrom receive destinationType to know to which type specifically we are converting sourceValue.
/// - ConvertTo and ConvertFrom receive formatProvider and ignoreCase.
/// Other differences to System.ComponentModel.TypeConverter:
/// - There is no ITypeDescriptorContext.
/// - This class is abstract
/// </remarks>
public abstract class PSTypeConverter
{
private static object GetSourceValueAsObject ( PSObject sourceValue )
{
if ( sourceValue == null )
{
return null ;
}
if ( sourceValue . BaseObject is PSCustomObject )
{
return sourceValue ;
}
else
{
return PSObject . Base ( sourceValue );
}
}
/// <summary>
/// Determines if the converter can convert the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter.
/// </summary>
/// <param name="sourceValue">value supposedly *not* of the types supported by this converted to be converted to the <paramref name="destinationType"/> parameter</param>
/// <param name="destinationType">one of the types supported by this converter to which the <paramref name="sourceValue"/> parameter should be converted</param>
/// <returns>True if the converter can convert the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter, otherwise false.</returns>
public abstract bool CanConvertFrom ( object sourceValue , Type destinationType );
/// <summary>
/// Determines if the converter can convert the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter.
/// </summary>
/// <param name="sourceValue">value supposedly *not* of the types supported by this converted to be converted to the <paramref name="destinationType"/> parameter</param>
/// <param name="destinationType">one of the types supported by this converter to which the <paramref name="sourceValue"/> parameter should be converted</param>
/// <returns>True if the converter can convert the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter, otherwise false.</returns>
public virtual bool CanConvertFrom ( PSObject sourceValue , Type destinationType )
{
return this . CanConvertFrom ( GetSourceValueAsObject ( sourceValue ), destinationType );
}
/// <summary>
/// Converts the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter using formatProvider and ignoreCase
/// </summary>
/// <param name="sourceValue">value supposedly *not* of the types supported by this converted to be converted to the <paramref name="destinationType"/> parameter</param>
/// <param name="destinationType">one of the types supported by this converter to which the <paramref name="sourceValue"/> parameter should be converted to</param>
/// <param name="formatProvider">The format provider to use like in IFormatable's ToString</param>
/// <param name="ignoreCase">true if case should be ignored</param>
/// <returns>the <paramref name="sourceValue"/> parameter converted to the <paramref name="destinationType"/> parameter using formatProvider and ignoreCase</returns>
/// <exception cref="InvalidCastException">if no conversion was possible</exception>
public abstract object ConvertFrom ( object sourceValue , Type destinationType , IFormatProvider formatProvider , bool ignoreCase );
/// <summary>
/// Converts the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter using formatProvider and ignoreCase
/// </summary>
/// <param name="sourceValue">value supposedly *not* of the types supported by this converted to be converted to the <paramref name="destinationType"/> parameter</param>
/// <param name="destinationType">one of the types supported by this converter to which the <paramref name="sourceValue"/> parameter should be converted to</param>
/// <param name="formatProvider">The format provider to use like in IFormatable's ToString</param>
/// <param name="ignoreCase">true if case should be ignored</param>
/// <returns>the <paramref name="sourceValue"/> parameter converted to the <paramref name="destinationType"/> parameter using formatProvider and ignoreCase</returns>
/// <exception cref="InvalidCastException">if no conversion was possible</exception>
public virtual object ConvertFrom ( PSObject sourceValue , Type destinationType , IFormatProvider formatProvider , bool ignoreCase )
{
return this . ConvertFrom ( GetSourceValueAsObject ( sourceValue ), destinationType , formatProvider , ignoreCase );
}
/// <summary>
/// Returns true if the converter can convert the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter
/// </summary>
/// <param name="sourceValue">value supposedly from one of the types supported by this converter to be converted to the <paramref name="destinationType"/> parameter</param>
/// <param name="destinationType">type to convert the <paramref name="sourceValue"/> parameter, supposedly not one of the types supported by the converter</param>
/// <returns>True if the converter can convert the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter, otherwise false.</returns>
public abstract bool CanConvertTo ( object sourceValue , Type destinationType );
/// <summary>
/// Returns true if the converter can convert the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter
/// </summary>
/// <param name="sourceValue">value supposedly from one of the types supported by this converter to be converted to the <paramref name="destinationType"/> parameter</param>
/// <param name="destinationType">type to convert the <paramref name="sourceValue"/> parameter, supposedly not one of the types supported by the converter</param>
/// <returns>True if the converter can convert the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter, otherwise false.</returns>
public virtual bool CanConvertTo ( PSObject sourceValue , Type destinationType )
{
return this . CanConvertTo ( GetSourceValueAsObject ( sourceValue ), destinationType );
}
/// <summary>
/// Converts the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter using formatProvider and ignoreCase
/// </summary>
/// <param name="sourceValue">value supposedly from one of the types supported by this converter to be converted to the <paramref name="destinationType"/> parameter</param>
/// <param name="destinationType">type to convert the <paramref name="sourceValue"/> parameter, supposedly not one of the types supported by the converter</param>
/// <param name="formatProvider">The format provider to use like in IFormatable's ToString</param>
/// <param name="ignoreCase">true if case should be ignored</param>
/// <returns>sourceValue converted to the <paramref name="destinationType"/> parameter using formatProvider and ignoreCase</returns>
/// <exception cref="InvalidCastException">if no conversion was possible</exception>
public abstract object ConvertTo ( object sourceValue , Type destinationType , IFormatProvider formatProvider , bool ignoreCase );
/// <summary>
/// Converts the <paramref name="sourceValue"/> parameter to the <paramref name="destinationType"/> parameter using formatProvider and ignoreCase
/// </summary>
/// <param name="sourceValue">value supposedly from one of the types supported by this converter to be converted to the <paramref name="destinationType"/> parameter</param>
/// <param name="destinationType">type to convert the <paramref name="sourceValue"/> parameter, supposedly not one of the types supported by the converter</param>
/// <param name="formatProvider">The format provider to use like in IFormatable's ToString</param>
/// <param name="ignoreCase">true if case should be ignored</param>
/// <returns>sourceValue converted to the <paramref name="destinationType"/> parameter using formatProvider and ignoreCase</returns>
/// <exception cref="InvalidCastException">if no conversion was possible</exception>
public virtual object ConvertTo ( PSObject sourceValue , Type destinationType , IFormatProvider formatProvider , bool ignoreCase )
{
return this . ConvertTo ( GetSourceValueAsObject ( sourceValue ), destinationType , formatProvider , ignoreCase );
}
}
/// <summary>
/// Enables a type that only has conversion from string to be converted from all other
/// types through string
/// </summary>
/// <remarks>
/// It is permitted to subclass <see cref="ConvertThroughString"/>
/// but there is no established scenario for doing this, nor has it been tested.
/// </remarks>
public class ConvertThroughString : PSTypeConverter
{
/// <summary>
/// This will return false only if sourceValue is string
/// </summary>
/// <param name="sourceValue">value to convert from</param>
/// <param name="destinationType">ignored</param>
/// <returns>false only if sourceValue is string</returns>
public override bool CanConvertFrom ( object sourceValue , Type destinationType )
{
// This if avoids infinite recursion.
if ( sourceValue is string )
{
return false ;
}
return true ;
}
/// <summary>
/// Converts to destinationType by first converting sourceValue to string
/// and then converting the result to destinationType.
/// </summary>
/// <param name="sourceValue">The value to convert from</param>
/// <param name="destinationType">The type this converter is associated with</param>
/// <param name="formatProvider">The IFormatProvider to use</param>
/// <param name="ignoreCase">true if case should be ignored</param>
/// <returns>sourceValue converted to destinationType</returns>
/// <exception cref="PSInvalidCastException">When no conversion was possible</exception>
public override object ConvertFrom ( object sourceValue , Type destinationType , IFormatProvider formatProvider , bool ignoreCase )
{
string sourceAsString = ( string ) LanguagePrimitives . ConvertTo ( sourceValue , typeof ( string ), formatProvider );
return LanguagePrimitives . ConvertTo ( sourceAsString , destinationType , formatProvider );
}
/// <summary>
/// Returns false, since this converter is not designed to be used to
/// convert from the type associated with the converted to other types.
/// </summary>
/// <param name="sourceValue">The value to convert from</param>
/// <param name="destinationType">The value to convert from</param>
/// <returns>false</returns>
public override bool CanConvertTo ( object sourceValue , Type destinationType )
{
return false ;
}
/// <summary>
/// Throws NotSupportedException, since this converter is not designed to be used to
/// convert from the type associated with the converted to other types.
/// </summary>
/// <param name="sourceValue">The value to convert from</param>
/// <param name="destinationType">The value to convert from</param>
/// <param name="formatProvider">The IFormatProvider to use</param>
/// <param name="ignoreCase">true if case should be ignored</param>
/// <returns>This method does not return a value.</returns>
/// <exception cref="NotSupportedException">NotSupportedException is always thrown</exception>
public override object ConvertTo ( object sourceValue , Type destinationType , IFormatProvider formatProvider , bool ignoreCase )
{
throw PSTraceSource . NewNotSupportedException ();
}
}
#endregion public type converters
/// <summary>
/// The ranking of versions for comparison purposes (used in overload resolution.)
/// A larger value means the conversion is better.
///
/// Note that the lower nibble is all ones for named conversion ranks. This allows for
/// conversions with rankings in between the named values. For example, int=>string[]
/// is value dependent, if the conversion from int=>string succeeds, then an array is
/// created, otherwise we try some other conversion. The int=>string[] conversion should
/// be worse than int=>string, but it is probably better than many other conversions, so
/// we want it to be only slightly worse than int=>string.
/// </summary>
/// <remarks>
/// ValueDependent is a flag, but we don't mark the enum as flags because it really isn't
/// a flags enum.
/// To make debugging easier, the "in between" conversions are all named, though there are
/// no references in the code. They all use the suffix S2A which means "scalar to array".
/// </remarks>
internal enum ConversionRank
{
None = 0x0000 ,
UnrelatedArraysS2A = 0x0007 ,
UnrelatedArrays = 0x000F ,
ToStringS2A = 0x0017 ,
ToString = 0x001F ,
CustomS2A = 0x0027 ,
Custom = 0x002F ,
IConvertibleS2A = 0x0037 ,
IConvertible = 0x003F ,
ImplicitCastS2A = 0x0047 ,
ImplicitCast = 0x004F ,
ExplicitCastS2A = 0x0057 ,
ExplicitCast = 0x005F ,
ConstructorS2A = 0x0067 ,
Constructor = 0x006F ,
Create = 0x0073 ,
ParseS2A = 0x0077 ,
Parse = 0x007F ,
PSObjectS2A = 0x0087 ,
PSObject = 0x008F ,
LanguageS2A = 0x0097 ,
Language = 0x009F ,
NullToValue = 0x00AF ,
NullToRef = 0x00BF ,
NumericExplicitS2A = 0x00C7 ,
NumericExplicit = 0x00CF ,
NumericExplicit1S2A = 0x00D7 ,
NumericExplicit1 = 0x00DF ,
NumericStringS2A = 0x00E7 ,
NumericString = 0x00EF ,
NumericImplicitS2A = 0x00F7 ,
NumericImplicit = 0x00FF ,
AssignableS2A = 0x0107 ,
Assignable = 0x010F ,
IdentityS2A = 0x0117 ,
StringToCharArray = 0x011A ,
Identity = 0x011F ,
ValueDependent = 0xFFF7 ,
}
/// <summary>
/// Defines language support methods
/// </summary>
[SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "Refactoring LanguagePrimitives takes lot of dev/test effort. Since V1 code is already shipped, we tend to exclude this message.")]
public static class LanguagePrimitives
{
[TraceSource("ETS", "Extended Type System")]
static private PSTraceSource tracer = PSTraceSource . GetTracer ( "ETS" , "Extended Type System" );
internal delegate void MemberNotFoundError ( PSObject pso , DictionaryEntry property , Type resultType );
internal delegate void MemberSetValueError ( SetValueException e );
internal const String OrderedAttribute = "ordered" ;
internal static void CreateMemberNotFoundError ( PSObject pso , DictionaryEntry property , Type resultType )
{
String availableProperties = GetAvailableProperties ( pso );
string message = StringUtil . Format ( ExtendedTypeSystem . PropertyNotFound , property . Key . ToString (), resultType . FullName , availableProperties );
typeConversion . WriteLine ( "Issuing an error message about not being able to create an object from hashtable." );
throw new InvalidOperationException ( message );
}
internal static void CreateMemberSetValueError ( SetValueException e )
{
typeConversion . WriteLine ( "Issuing an error message about not being able to set the properties for an object." );
throw e ;
}
static LanguagePrimitives ()
{
RebuildConversionCache ();
InitializeGetEnumerableCache ();
#if ! CORECLR // AppDomain Not In CoreCLR
AppDomain . CurrentDomain . AssemblyResolve += AssemblyResolveHelper ;
#endif
}
internal static void UpdateTypeConvertFromTypeTable ( string typeName )
{
lock ( converterCache )
{
var toRemove = converterCache . Keys . Where (
conv => string . Equals ( conv . to . FullName , typeName , StringComparison . OrdinalIgnoreCase ) ||
string . Equals ( conv . from . FullName , typeName , StringComparison . OrdinalIgnoreCase )). ToArray ();
foreach ( var k in toRemove )
{
converterCache . Remove ( k );
}
// Note we do not clear possibleTypeConverter even when removing.
//
// The conversion cache and the possibleTypeConverter cache are process wide, but
// the type table used for any specific conversion is runspace specific.
possibleTypeConverter [ typeName ] = true ;
}
}
#region GetEnumerable / GetEnumerator
/// <summary>
/// This is a wrapper class that allows us to use the generic IEnumerable
/// implementation of an object when we can't use it's non-generic
/// implementation.
/// </summary>
private class EnumerableTWrapper : IEnumerable
{
object _enumerable ;
Type _enumerableType ;
DynamicMethod _getEnumerator ;
internal EnumerableTWrapper ( object enumerable , Type enumerableType )
{
_enumerable = enumerable ;
_enumerableType = enumerableType ;
CreateGetEnumerator ();
}
private void CreateGetEnumerator ()
{
_getEnumerator = new DynamicMethod ( "GetEnumerator" , typeof ( object ),
new Type [] { typeof ( object ) }, typeof ( LanguagePrimitives ). GetTypeInfo (). Module , true );
ILGenerator emitter = _getEnumerator . GetILGenerator ();
emitter . Emit ( OpCodes . Ldarg_0 );
emitter . Emit ( OpCodes . Castclass , _enumerableType );
MethodInfo methodInfo = _enumerableType . GetMethod ( "GetEnumerator" , new Type [] { });
emitter . Emit ( OpCodes . Callvirt , methodInfo );
emitter . Emit ( OpCodes . Ret );
}
#region IEnumerable Members
public IEnumerator GetEnumerator ()
{
return ( IEnumerator ) _getEnumerator . Invoke ( null , new object [] { _enumerable });
}
#endregion
}
private static IEnumerable GetEnumerableFromIEnumerableT ( object obj )
{
foreach ( Type i in obj . GetType (). GetInterfaces ())
{
TypeInfo typeinfo = i . GetTypeInfo ();
if ( typeinfo . IsGenericType && typeinfo . GetGenericTypeDefinition () == typeof ( IEnumerable <>))
{
return new EnumerableTWrapper ( obj , i );
}
}
return null ;
}
delegate IEnumerable GetEnumerableDelegate ( object obj );
static Dictionary < Type , GetEnumerableDelegate > getEnumerableCache = new Dictionary < Type , GetEnumerableDelegate >( 32 );
static GetEnumerableDelegate GetOrCalculateEnumerable ( Type type )
{
GetEnumerableDelegate getEnumerable = null ;
lock ( getEnumerableCache )
{
if (! getEnumerableCache . TryGetValue ( type , out getEnumerable ))
{
getEnumerable = CalculateGetEnumerable ( type );
getEnumerableCache . Add ( type , getEnumerable );
}
}
return getEnumerable ;
}
static void InitializeGetEnumerableCache ()
{
lock ( getEnumerableCache )
{
// PowerShell doesn't treat strings as enumerables so just return null.
// we also want to return null on common numeric types very quickly
getEnumerableCache . Clear ();
getEnumerableCache . Add ( typeof ( string ), LanguagePrimitives . ReturnNullEnumerable );
getEnumerableCache . Add ( typeof ( int ), LanguagePrimitives . ReturnNullEnumerable );
getEnumerableCache . Add ( typeof ( double ), LanguagePrimitives . ReturnNullEnumerable );
}
}
internal static bool IsTypeEnumerable ( Type type )
{
GetEnumerableDelegate getEnumerable = GetOrCalculateEnumerable ( type );
return ( getEnumerable != LanguagePrimitives . ReturnNullEnumerable );
}
/// <summary>
/// Retrieves the IEnumerable of obj or null if the language does not consider obj to be IEnumerable
/// </summary>
/// <param name="obj">
/// IEnumerable or IEnumerable-like object
/// </param>
[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "Since V1 code is already shipped, excluding this message.")]
public static IEnumerable GetEnumerable ( object obj )
{
if ( obj == null )
{
return null ;
}
Type objectType = obj . GetType ();
// if the object passed is an PSObject,
// look at the base object. Notice that, if the
// object has been serialized, the base object
// will be there as an ArrayList if the original
// object was IEnumerable
if ( objectType == typeof ( PSObject ))
{
PSObject mshObj = ( PSObject ) obj ;
obj = mshObj . BaseObject ;
objectType = obj . GetType ();
}
GetEnumerableDelegate getEnumerable = GetOrCalculateEnumerable ( objectType );
return getEnumerable ( obj );
}
static IEnumerable ReturnNullEnumerable ( object obj )
{
return null ;
}
2016-04-06 12:01:07 -07:00
#if ! CORECLR
// .NET Core does not have a full DataTable type
2016-03-30 14:20:52 -07:00
static IEnumerable DataTableEnumerable ( object obj )
{
return ((( DataTable ) obj ). Rows );
}
2016-04-06 12:01:07 -07:00
#endif
2016-03-30 14:20:52 -07:00
static IEnumerable TypicalEnumerable ( object obj )
{
IEnumerable e = ( IEnumerable ) obj ;
try
{
// Some IEnumerable implementations just return null. Others
// raise an exception. Either of these may have a perfectly
// good generic implementation, so we'll try those if the
// non-generic is no good.
if ( e . GetEnumerator () == null )
{
return GetEnumerableFromIEnumerableT ( obj );
}
return e ;
}
catch ( Exception innerException )
{
CommandProcessorBase . CheckForSevereException ( innerException );
e = GetEnumerableFromIEnumerableT ( obj );
if ( e != null )
{
return e ;
}
throw new ExtendedTypeSystemException (
"ExceptionInGetEnumerator" ,
innerException ,
ExtendedTypeSystem . EnumerationException ,
innerException . Message );
}
}
static GetEnumerableDelegate CalculateGetEnumerable ( Type objectType )
{
2016-04-06 12:01:07 -07:00
#if ! CORECLR
// .NET Core does not have a full DataTable type
2016-03-30 14:20:52 -07:00
if ( typeof ( DataTable ). IsAssignableFrom ( objectType ))
{
return LanguagePrimitives . DataTableEnumerable ;
}
2016-04-06 12:01:07 -07:00
#endif
2016-03-30 14:20:52 -07:00
// Don't treat IDictionary or XmlNode as enumerable...
if ( typeof ( IEnumerable ). IsAssignableFrom ( objectType )
&& ! typeof ( IDictionary ). IsAssignableFrom ( objectType )
&& ! typeof ( XmlNode ). IsAssignableFrom ( objectType ))
{
return LanguagePrimitives . TypicalEnumerable ;
}
return LanguagePrimitives . ReturnNullEnumerable ;
}
private static readonly CallSite < Func < CallSite , object , IEnumerator >> _getEnumeratorSite =
CallSite < Func < CallSite , object , IEnumerator >>. Create ( PSEnumerableBinder . Get ());
/// <summary>
/// Retrieves the IEnumerator of obj or null if the language does not consider obj as capable of returning an IEnumerator
/// </summary>
/// <param name="obj">
/// IEnumerable or IEnumerable-like object
/// </param>
/// <exception cref="ExtendedTypeSystemException">When the act of getting the enumerator throws an exception</exception>
[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "Since V1 code is already shipped, excluding this message for backward compatibility reasons.")]
public static IEnumerator GetEnumerator ( object obj )
{
var result = _getEnumeratorSite . Target . Invoke ( _getEnumeratorSite , obj );
return ( result is EnumerableOps . NonEnumerableObjectEnumerator ) ? null : result ;
}
#endregion GetEnumerable / GetEnumerator
/// <summary>
/// This method takes a an arbitrary object and wraps it in a PSDataCollection of PSObject.
/// This simplifies interacting with the PowerShell workflow activities.
/// </summary>
/// <param name="inputValue"></param>
/// <returns></returns>
public static PSDataCollection < PSObject > GetPSDataCollection ( object inputValue )
{
PSDataCollection < PSObject > result = new PSDataCollection < PSObject >();
if ( inputValue != null )
{
IEnumerator e = GetEnumerator ( inputValue );
if ( e != null )
{
while ( e . MoveNext ())
{
result . Add ( e . Current == null ? null : PSObject . AsPSObject ( e . Current ));
}
}
else
{
result . Add ( PSObject . AsPSObject ( inputValue ));
}
}
result . Complete ();
return result ;
}
/// <summary>
/// Used to compare two objects for equality converting the second to the type of the first, if required.
/// </summary>
/// <param name="first">first object</param>
/// <param name="second">object to compare first to</param>
/// <returns>true if first is equal to the second</returns>
public new static bool Equals ( object first , object second )
{
return Equals ( first , second , false , CultureInfo . InvariantCulture );
}
/// <summary>
/// Used to compare two objects for equality converting the second to the type of the first, if required.
/// </summary>
/// <param name="first">first object</param>
/// <param name="second">object to compare first to</param>
/// <param name="ignoreCase">used only if first and second are strings
/// to specify the type of string comparison </param>
/// <returns>true if first is equal to the second</returns>
public static bool Equals ( object first , object second , bool ignoreCase )
{
return Equals ( first , second , ignoreCase , CultureInfo . InvariantCulture );
}
/// <summary>
/// Used to compare two objects for equality converting the second to the type of the first, if required.
/// </summary>
/// <param name="first">first object</param>
/// <param name="second">object to compare first to</param>
/// <param name="ignoreCase">used only if first and second are strings
/// to specify the type of string comparison </param>
/// <param name="formatProvider">the format/culture to be used. If this parameter is null,
/// CultureInfo.InvariantCulture will be used.
/// </param>
/// <returns>true if first is equal to the second</returns>
public static bool Equals ( object first , object second , bool ignoreCase , IFormatProvider formatProvider )
{
// If both first and second are null it returns true.
// If one is null and the other is not it returns false.
// if (first.Equals(second)) it returns true otherwise it goes ahead with type conversion operations.
// If both first and second are strings it returns (String.Compare(firstString, secondString, ignoreCase) == 0).
// If second can be converted to the type of the first, it does so and returns first.Equals(secondConverted)
// Otherwise false is returned
if ( formatProvider == null )
{
formatProvider = CultureInfo . InvariantCulture ;
}
var culture = formatProvider as CultureInfo ;
if ( culture == null )
{
throw PSTraceSource . NewArgumentException ( "formatProvider" );
}
first = PSObject . Base ( first );
second = PSObject . Base ( second );
if ( first == null )
{
if ( second == null ) return true ;
return false ;
}
if ( second == null )
{
return false ; // first is not null
}
string firstString = first as string ;
string secondString ;
if ( firstString != null )
{
secondString = second as string ;
if ( secondString == null )
{
secondString = ( string ) LanguagePrimitives . ConvertTo ( second , typeof ( string ), culture );
}
return ( culture . CompareInfo . Compare ( firstString , secondString ,
ignoreCase ? CompareOptions . IgnoreCase : CompareOptions . None ) == 0 );
}
if ( first . Equals ( second )) return true ;
Type firstType = first . GetType ();
Type secondType = second . GetType ();
int firstIndex = LanguagePrimitives . TypeTableIndex ( firstType );
int secondIndex = LanguagePrimitives . TypeTableIndex ( secondType );
if (( firstIndex != - 1 ) && ( secondIndex != - 1 ))
{
return LanguagePrimitives . NumericCompare ( first , second , firstIndex , secondIndex ) == 0 ;
}
if ( firstType == typeof ( char ) && ignoreCase )
{
secondString = second as string ;
if ( secondString != null && secondString . Length == 1 )
{
char firstAsUpper = culture . TextInfo . ToUpper (( char ) first );
char secondAsUpper = culture . TextInfo . ToUpper ( secondString [ 0 ]);
return firstAsUpper . Equals ( secondAsUpper );
}
else if ( secondType == typeof ( char ))
{
char firstAsUpper = culture . TextInfo . ToUpper (( char ) first );
char secondAsUpper = culture . TextInfo . ToUpper (( char ) second );
return firstAsUpper . Equals ( secondAsUpper );
}
}
try
{
object secondConverted = LanguagePrimitives . ConvertTo ( second , firstType , culture );
return first . Equals ( secondConverted );
}
catch ( InvalidCastException )
{
}
return false ;
}
/// <summary>
/// Compare first and second, converting second to the
/// type of the first, if necessary.
/// </summary>
/// <param name="first">first comparison value</param>
/// <param name="second">second comparison value</param>
/// <returns>less than zero if first is smaller than second, more than
/// zero if it is greater or zero if they are the same</returns>
/// <exception cref="System.ArgumentException">
/// <paramref name="first"/> does not implement IComparable or <paramref name="second"/> cannot be converted
/// to the type of <paramref name="first"/>.
/// </exception>
public static int Compare ( object first , object second )
{
return LanguagePrimitives . Compare ( first , second , false , CultureInfo . InvariantCulture );
}
/// <summary>
/// Compare first and second, converting second to the
/// type of the first, if necessary.
/// </summary>
/// <param name="first">first comparison value</param>
/// <param name="second">second comparison value</param>
/// <param name="ignoreCase">Used if both values are strings</param>
/// <returns>less than zero if first is smaller than second, more than
/// zero if it is greater or zero if they are the same</returns>
/// <exception cref="System.ArgumentException">
/// <paramref name="first"/> does not implement IComparable or <paramref name="second"/> cannot be converted
/// to the type of <paramref name="first"/>.
/// </exception>
public static int Compare ( object first , object second , bool ignoreCase )
{
return LanguagePrimitives . Compare ( first , second , ignoreCase , CultureInfo . InvariantCulture );
}
/// <summary>
/// Compare first and second, converting second to the
/// type of the first, if necessary.
/// </summary>
/// <param name="first">first comparison value</param>
/// <param name="second">second comparison value</param>
/// <param name="ignoreCase">Used if both values are strings</param>
/// <param name="formatProvider">Used in type conversions and if both values are strings</param>
/// <returns>less than zero if first is smaller than second, more than
/// zero if it is greater or zero if they are the same</returns>
/// <exception cref="System.ArgumentException">
/// <paramref name="first"/> does not implement IComparable or <paramref name="second"/> cannot be converted
/// to the type of <paramref name="first"/>.
/// </exception>
public static int Compare ( object first , object second , bool ignoreCase , IFormatProvider formatProvider )
{
if ( formatProvider == null )
{
formatProvider = CultureInfo . InvariantCulture ;
}
var culture = formatProvider as CultureInfo ;
if ( culture == null )
{
throw PSTraceSource . NewArgumentException ( "formatProvider" );
}
first = PSObject . Base ( first );
second = PSObject . Base ( second );
if ( first == null )
{
if ( second == null )
{
return 0 ;
}
else
{
// If it's a positive number, including 0, it's greater than null
// for everything else it's less than zero...
switch ( LanguagePrimitives . GetTypeCode ( second . GetType ()))
{
case TypeCode . Int16 : return System . Math . Sign (( Int16 ) second ) < 0 ? 1 : - 1 ;
case TypeCode . Int32 : return System . Math . Sign (( Int32 ) second ) < 0 ? 1 : - 1 ;
case TypeCode . Int64 : return System . Math . Sign (( Int64 ) second ) < 0 ? 1 : - 1 ;
case TypeCode . SByte : return System . Math . Sign (( sbyte ) second ) < 0 ? 1 : - 1 ;
case TypeCode . Single : return System . Math . Sign (( System . Single ) second ) < 0 ? 1 : - 1 ;
case TypeCode . Double : return System . Math . Sign (( System . Double ) second ) < 0 ? 1 : - 1 ;
case TypeCode . Decimal : return System . Math . Sign (( System . Decimal ) second ) < 0 ? 1 : - 1 ;
default : return - 1 ;
}
}
}
if ( second == null )
{
// If it's a positive number, including 0, it's greater than null
// for everything else it's less than zero...
switch ( LanguagePrimitives . GetTypeCode ( first . GetType ()))
{
case TypeCode . Int16 : return System . Math . Sign (( Int16 ) first ) < 0 ? - 1 : 1 ;
case TypeCode . Int32 : return System . Math . Sign (( Int32 ) first ) < 0 ? - 1 : 1 ;
case TypeCode . Int64 : return System . Math . Sign (( Int64 ) first ) < 0 ? - 1 : 1 ;
case TypeCode . SByte : return System . Math . Sign (( sbyte ) first ) < 0 ? - 1 : 1 ;
case TypeCode . Single : return System . Math . Sign (( System . Single ) first ) < 0 ? - 1 : 1 ;
case TypeCode . Double : return System . Math . Sign (( System . Double ) first ) < 0 ? - 1 : 1 ;
case TypeCode . Decimal : return System . Math . Sign (( System . Decimal ) first ) < 0 ? - 1 : 1 ;
default : return 1 ;
}
}
string firstString = first as string ;
if ( firstString != null )
{
string secondString = second as string ;
if ( secondString == null )
{
try
{
secondString = ( string ) LanguagePrimitives . ConvertTo ( second , typeof ( string ), culture );
}
catch ( PSInvalidCastException e )
{
throw PSTraceSource . NewArgumentException ( "second" , ExtendedTypeSystem . ComparisonFailure ,
first . ToString (), second . ToString (), e . Message );
}
}
return culture . CompareInfo . Compare ( firstString , secondString ,
ignoreCase ? CompareOptions . IgnoreCase : CompareOptions . None );
}
Type firstType = first . GetType ();
Type secondType = second . GetType ();
int firstIndex = LanguagePrimitives . TypeTableIndex ( firstType );
int secondIndex = LanguagePrimitives . TypeTableIndex ( secondType );
if (( firstIndex != - 1 ) && ( secondIndex != - 1 ))
{
return LanguagePrimitives . NumericCompare ( first , second , firstIndex , secondIndex );
}
object secondConverted ;
try
{
secondConverted = LanguagePrimitives . ConvertTo ( second , firstType , culture );
}
catch ( PSInvalidCastException e )
{
throw PSTraceSource . NewArgumentException ( "second" , ExtendedTypeSystem . ComparisonFailure ,
first . ToString (), second . ToString (), e . Message );
}
IComparable firstComparable = first as IComparable ;
if ( firstComparable != null )
{
return firstComparable . CompareTo ( secondConverted );
}
if ( first . Equals ( second ))
{
return 0 ;
}
// At this point, we know that they aren't equal but we have no way of
// knowing which should compare greater than the other so we throw an exception.
throw PSTraceSource . NewArgumentException ( "first" , ExtendedTypeSystem . NotIcomparable , first . ToString ());
}
/// <summary>
/// Returns true if the language considers obj to be true
/// </summary>
/// <param name="obj">obj to verify if it is true</param>
/// <returns>true if obj is true</returns>
[SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "obj", Justification = "Since V1 code is already shipped, excluding this message for backward compatibility reasons")]
public static bool IsTrue ( object obj )
{
// null is a valid argument - it converts to false...
if ( obj == null || obj == AutomationNull . Value )
return false ;
obj = PSObject . Base ( obj );
Type objType = obj . GetType ();
if ( objType == typeof ( bool ))
{
return ( bool ) obj ;
}
if ( objType == typeof ( string ))
{
return IsTrue (( string ) obj );
}
if ( LanguagePrimitives . IsNumeric ( LanguagePrimitives . GetTypeCode ( objType )))
{
ConversionData data = GetConversionData ( objType , typeof ( bool )) ??
CacheConversion ( objType , typeof ( bool ), CreateNumericToBoolConverter ( objType ), ConversionRank . Language );
return ( bool ) data . Invoke ( obj , typeof ( bool ), false , null , null , null );
}
if ( objType == typeof ( SwitchParameter ))
return (( SwitchParameter ) obj ). ToBool ();
IList objectArray = obj as IList ;
if ( objectArray != null )
{
return IsTrue ( objectArray );
}
return true ;
}
internal static bool IsTrue ( string s )
{
return ( s . Length != 0 );
}
internal static bool IsTrue ( IList objectArray )
{
switch ( objectArray . Count )
{
// a zero length array is false, so condition is false
case 0 :
return false ;
// if the result is an array of length 1, treat it as a scalar...
case 1 :
// A possible implementation would be just
// return IsTrue(objectArray[0]);
// but since we don't want this to recurse indefinately
// we explicitly check the case where it would recurse
// and deal with it.
IList firstElement = objectArray [ 0 ] as IList ;
if ( firstElement == null )
{
return IsTrue ( objectArray [ 0 ]);
}
if ( firstElement . Count < 1 ) return false ;
// the first element is an array with more than zero elements
return true ;
default :
return true ;
}
}
/// <summary>
/// Internal routine that determines if an object meets any of our criteria for null.
/// </summary>
/// <param name="obj">The object to test</param>
/// <returns>true if the object is null</returns>
internal static bool IsNull ( object obj )
{
return ( obj == null || obj == AutomationNull . Value );
}
/// <summary>
/// Auxilliary for the cases where we want a new PSObject or null
/// </summary>
internal static PSObject AsPSObjectOrNull ( object obj )
{
if ( obj == null )
{
return null ;
}
return PSObject . AsPSObject ( obj );
}
internal static int TypeTableIndex ( Type type )
{
switch ( LanguagePrimitives . GetTypeCode ( type ))
{
case TypeCode . Int16 : return 0 ;
case TypeCode . Int32 : return 1 ;
case TypeCode . Int64 : return 2 ;
case TypeCode . UInt16 : return 3 ;
case TypeCode . UInt32 : return 4 ;
case TypeCode . UInt64 : return 5 ;
case TypeCode . SByte : return 6 ;
case TypeCode . Byte : return 7 ;
case TypeCode . Single : return 8 ;
case TypeCode . Double : return 9 ;
case TypeCode . Decimal : return 10 ;
default : return - 1 ;
}
}
/// <summary>
/// Table of the largest safe type to which both types can be converted without exceptions.
/// This table is used for numeric comparisons.
/// The 4 entries marked as not used, are explicitly dealt with in NumericCompareDecimal.
/// NumericCompareDecimal exists because doubles and singles can throw
/// an exception when converted to decimal.
/// The order of lines and columns cannot be changed since NumericCompare depends on it.
/// </summary>
internal static Type [][] LargestTypeTable = new Type [][]
{
// System.Int16 System.Int32 System.Int64 System.UInt16 System.UInt32 System.UInt64 System.SByte System.Byte System.Single System.Double System.Decimal
/* System.Int16 */ new Type [] { typeof ( System . Int16 ), typeof ( System . Int32 ), typeof ( System . Int64 ), typeof ( System . Int32 ), typeof ( System . Int64 ), typeof ( System . Double ), typeof ( System . Int16 ), typeof ( System . Int16 ), typeof ( System . Single ), typeof ( System . Double ), typeof ( System . Decimal ) },
/* System.Int32 */ new Type [] { typeof ( System . Int32 ), typeof ( System . Int32 ), typeof ( System . Int64 ), typeof ( System . Int32 ), typeof ( System . Int64 ), typeof ( System . Double ), typeof ( System . Int32 ), typeof ( System . Int32 ), typeof ( System . Double ), typeof ( System . Double ), typeof ( System . Decimal ) },
/* System.Int64 */ new Type [] { typeof ( System . Int64 ), typeof ( System . Int64 ), typeof ( System . Int64 ), typeof ( System . Int64 ), typeof ( System . Int64 ), typeof ( System . Decimal ), typeof ( System . Int64 ), typeof ( System . Int64 ), typeof ( System . Double ), typeof ( System . Double ), typeof ( System . Decimal ) },
/* System.UInt16 */ new Type [] { typeof ( System . Int32 ), typeof ( System . Int32 ), typeof ( System . Int64 ), typeof ( System . UInt16 ), typeof ( System . UInt32 ), typeof ( System . UInt64 ), typeof ( System . Int32 ), typeof ( System . UInt16 ), typeof ( System . Single ), typeof ( System . Double ), typeof ( System . Decimal ) },
/* System.UInt32 */ new Type [] { typeof ( System . Int64 ), typeof ( System . Int64 ), typeof ( System . Int64 ), typeof ( System . UInt32 ), typeof ( System . UInt32 ), typeof ( System . UInt64 ), typeof ( System . Int64 ), typeof ( System . UInt32 ), typeof ( System . Double ), typeof ( System . Double ), typeof ( System . Decimal ) },
/* System.UInt64 */ new Type [] { typeof ( System . Double ), typeof ( System . Double ), typeof ( System . Decimal ), typeof ( System . UInt64 ), typeof ( System . UInt64 ), typeof ( System . UInt64 ), typeof ( System . Double ), typeof ( System . UInt64 ), typeof ( System . Double ), typeof ( System . Double ), typeof ( System . Decimal ) },
/* System.SByte */ new Type [] { typeof ( System . Int16 ), typeof ( System . Int32 ), typeof ( System . Int64 ), typeof ( System . Int32 ), typeof ( System . Int64 ), typeof ( System . Double ), typeof ( System . SByte ), typeof ( System . Int16 ), typeof ( System . Single ), typeof ( System . Double ), typeof ( System . Decimal ) },
/* System.Byte */ new Type [] { typeof ( System . Int16 ), typeof ( System . Int32 ), typeof ( System . Int64 ), typeof ( System . UInt16 ), typeof ( System . UInt32 ), typeof ( System . UInt64 ), typeof ( System . Int16 ), typeof ( System . Byte ), typeof ( System . Single ), typeof ( System . Double ), typeof ( System . Decimal ) },
/* System.Single */ new Type [] { typeof ( System . Single ), typeof ( System . Double ), typeof ( System . Double ), typeof ( System . Single ), typeof ( System . Double ), typeof ( System . Double ), typeof ( System . Single ), typeof ( System . Single ), typeof ( System . Single ), typeof ( System . Double ), null /*not used*/ },
/* System.Double */ new Type [] { typeof ( System . Double ), typeof ( System . Double ), typeof ( System . Double ), typeof ( System . Double ), typeof ( System . Double ), typeof ( System . Double ), typeof ( System . Double ), typeof ( System . Double ), typeof ( System . Double ), typeof ( System . Double ), null /*not used*/ },
/* System.Decimal */ new Type [] { typeof ( System . Decimal ), typeof ( System . Decimal ), typeof ( System . Decimal ), typeof ( System . Decimal ), typeof ( System . Decimal ), typeof ( System . Decimal ), typeof ( System . Decimal ), typeof ( System . Decimal ), null /*not used*/ , null /*not used*/ , typeof ( System . Decimal ) },
};
private static int NumericCompareDecimal ( decimal decimalNumber , object otherNumber )
{
object otherDecimal = null ;
try
{
otherDecimal = Convert . ChangeType ( otherNumber , typeof ( System . Decimal ), CultureInfo . InvariantCulture );
}
catch ( OverflowException )
{
try
{
double wasDecimal = ( double ) Convert . ChangeType ( decimalNumber , typeof ( System . Double ), CultureInfo . InvariantCulture );
double otherDouble = ( double ) Convert . ChangeType ( otherNumber , typeof ( System . Double ), CultureInfo . InvariantCulture );
return (( IComparable ) wasDecimal ). CompareTo ( otherDouble );
}
catch ( Exception e ) // We need to catch the generic exception because ChangeType throws unadvertised exceptions
{
CommandProcessorBase . CheckForSevereException ( e );
return - 1 ;
}
}
catch ( Exception e ) // We need to catch the generic exception because ChangeType throws unadvertised exceptions
{
CommandProcessorBase . CheckForSevereException ( e );
return - 1 ;
}
return (( IComparable ) decimalNumber ). CompareTo ( otherDecimal );
}
private static int NumericCompare ( object number1 , object number2 , int index1 , int index2 )
{
// Conversion from single or double to decimal might throw
// if the double is greater than the decimal's maximum so
// we special case it in NumericCompareDecimal
if (( index1 == 10 ) && (( index2 == 8 ) || ( index2 == 9 )))
{
return NumericCompareDecimal (( decimal ) number1 , number2 );
}
if (( index2 == 10 ) && (( index1 == 8 ) || ( index1 == 9 )))
{
return - NumericCompareDecimal (( decimal ) number2 , number1 );
}
Type commonType = LargestTypeTable [ index1 ][ index2 ];
object number1Converted = Convert . ChangeType ( number1 , commonType , CultureInfo . InvariantCulture );
object number2Converted = Convert . ChangeType ( number2 , commonType , CultureInfo . InvariantCulture );
return (( IComparable ) number1Converted ). CompareTo ( number2Converted );
}
/// <summary>
/// Necessary not to return an integer type code for enums
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
internal static TypeCode GetTypeCode ( Type type )
{
return type . GetTypeCode ();
}
/// <summary>
/// Emulates the "As" C# language primitive, but will unwrap
/// the PSObject if required.
/// </summary>
/// <typeparam name="T">The type for which to convert</typeparam>
/// <param name="castObject">The object from which to convert</param>
/// <returns>An object of the specified type, if the conversion was successful. Returns null otherwise.</returns>
internal static T FromObjectAs < T >( Object castObject )
{
T returnType = default ( T );
// First, see if we can cast the direct type
PSObject wrapperObject = castObject as PSObject ;
if ( wrapperObject == null )
{
try
{
returnType = ( T ) castObject ;
}
catch ( InvalidCastException )
{
returnType = default ( T );
}
}
// Then, see if it is an PSObject wrapping the object
else
{
try
{
returnType = ( T ) wrapperObject . BaseObject ;
}
catch ( InvalidCastException )
{
returnType = default ( T );
}
}
return returnType ;
}
[Flags]
private enum TypeCodeTraits
{
None = 0x00 ,
SignedInteger = 0x01 ,
UnsignedInteger = 0x02 ,
Floating = 0x04 ,
CimIntrinsicType = 0x08 ,
Decimal = 0x10 ,
Integer = SignedInteger | UnsignedInteger ,
Numeric = Integer | Floating | Decimal ,
}
private static readonly TypeCodeTraits [] typeCodeTraits = new TypeCodeTraits []
{
/* Empty = 0 */ TypeCodeTraits . None ,
/* Object = 1 */ TypeCodeTraits . None ,
/* DBNull = 2 */ TypeCodeTraits . None ,
/* Boolean = 3 */ TypeCodeTraits . CimIntrinsicType ,
/* Char = 4 */ TypeCodeTraits . CimIntrinsicType ,
/* SByte = 5 */ TypeCodeTraits . SignedInteger | TypeCodeTraits . CimIntrinsicType ,
/* Byte = 6 */ TypeCodeTraits . UnsignedInteger | TypeCodeTraits . CimIntrinsicType ,
/* Int16 = 7 */ TypeCodeTraits . SignedInteger | TypeCodeTraits . CimIntrinsicType ,
/* UInt16 = 8 */ TypeCodeTraits . UnsignedInteger | TypeCodeTraits . CimIntrinsicType ,
/* Int32 = 9 */ TypeCodeTraits . SignedInteger | TypeCodeTraits . CimIntrinsicType ,
/* UInt32 = 10 */ TypeCodeTraits . UnsignedInteger | TypeCodeTraits . CimIntrinsicType ,
/* Int64 = 11 */ TypeCodeTraits . SignedInteger | TypeCodeTraits . CimIntrinsicType ,
/* UInt64 = 12 */ TypeCodeTraits . UnsignedInteger | TypeCodeTraits . CimIntrinsicType ,
/* Single = 13 */ TypeCodeTraits . Floating | TypeCodeTraits . CimIntrinsicType ,
/* Double = 14 */ TypeCodeTraits . Floating | TypeCodeTraits . CimIntrinsicType ,
/* Decimal = 15 */ TypeCodeTraits . Decimal ,
/* DateTime = 16 */ TypeCodeTraits . None | TypeCodeTraits . CimIntrinsicType ,
/* = 17 */ TypeCodeTraits . None ,
/* String = 18 */ TypeCodeTraits . None | TypeCodeTraits . CimIntrinsicType ,
};
/// <summary>
/// Verifies if type is a signed integer
/// </summary>
/// <param name="typeCode">type code to check</param>
/// <returns>true if type is a signed integer, false otherwise</returns>
internal static bool IsSignedInteger ( TypeCode typeCode )
{
return ( typeCodeTraits [( int ) typeCode ] & TypeCodeTraits . SignedInteger ) != 0 ;
}
/// <summary>
/// Verifies if type is an unsigned integer
/// </summary>
/// <param name="typeCode">type code to check</param>
/// <returns>true if type is an unsigned integer, false otherwise</returns>
internal static bool IsUnsignedInteger ( TypeCode typeCode )
{
return ( typeCodeTraits [( int ) typeCode ] & TypeCodeTraits . UnsignedInteger ) != 0 ;
}
/// <summary>
/// Verifies if type is integer
/// </summary>
/// <param name="typeCode">type code to check</param>
/// <returns>true if type is integer, false otherwise</returns>
internal static bool IsInteger ( TypeCode typeCode )
{
return ( typeCodeTraits [( int ) typeCode ] & TypeCodeTraits . Integer ) != 0 ;
}
/// <summary>
/// Verifies if type is a floating point number
/// </summary>
/// <param name="typeCode">type code to check</param>
/// <returns>true if type is floating point, false otherwise</returns>
internal static bool IsFloating ( TypeCode typeCode )
{
return ( typeCodeTraits [( int ) typeCode ] & TypeCodeTraits . Floating ) != 0 ;
}
/// <summary>
/// Verifies if type is an integer or floating point number
/// </summary>
/// <param name="typeCode">type code to check</param>
/// <returns>true if type is integer or floating point, false otherwise</returns>
internal static bool IsNumeric ( TypeCode typeCode )
{
return ( typeCodeTraits [( int ) typeCode ] & TypeCodeTraits . Numeric ) != 0 ;
}
/// <summary>
/// Verifies if type is a CIM intrinsic type
/// </summary>
/// <param name="typeCode">type code to check</param>
/// <returns>true if type is CIM intrinsic type, false otherwise</returns>
internal static bool IsCimIntrinsicScalarType ( TypeCode typeCode )
{
return ( typeCodeTraits [( int ) typeCode ] & TypeCodeTraits . CimIntrinsicType ) != 0 ;
}
internal static bool IsCimIntrinsicScalarType ( Type type )
{
Dbg . Assert ( type != null , "Caller should verify type != null" );
// using type code we can cover all intrinsic types from the table
// on page 11 of DSP0004, except:
// - TimeSpan part of "datetime"
// - <classname> ref
TypeCode typeCode = LanguagePrimitives . GetTypeCode ( type );
if ( LanguagePrimitives . IsCimIntrinsicScalarType ( typeCode ) && ! type . GetTypeInfo (). IsEnum )
{
return true ;
}
if ( type == typeof ( TimeSpan ))
{
return true ;
}
return false ;
}
/// <summary>
/// Verifies if type is one of the boolean types
/// </summary>
/// <param name="type">type to check</param>
/// <returns>true if type is one of boolean types, false otherwise</returns>
internal static bool IsBooleanType ( Type type )
{
if ( type == typeof ( bool ) ||
type == typeof ( Nullable < bool >))
return true ;
else
return false ;
}
/// <summary>
/// Verifies if type is one of switch parameter types
/// </summary>
/// <param name="type">type to check</param>
/// <returns>true if type is one of switch parameter types, false otherwise</returns>
internal static bool IsSwitchParameterType ( Type type )
{
if ( type == typeof ( SwitchParameter ) || type == typeof ( Nullable < SwitchParameter >))
return true ;
else
return false ;
}
/// <summary>
/// Verifies if type is one of boolean or switch parameter types
/// </summary>
/// <param name="type">type to check</param>
/// <returns>true if type if one of boolean or switch parameter types,
/// false otherwise</returns>
internal static bool IsBoolOrSwitchParameterType ( Type type )
{
if ( IsBooleanType ( type ) || IsSwitchParameterType ( type ))
return true ;
else
return false ;
}
/// <summary>
/// Do the necessary conversions when using property or array assignment to a generic dictionary:
///
/// $dict.Prop = value
/// $dict[$Prop] = value
///
/// The property typically won't need conversion, but it could. The value is more likely in
/// need of conversion.
/// </summary>
/// <param name="dictionary">The dictionary that potentially implement <see cref="IDictionary<TKey,TValue>"/></param>
/// <param name="key">The object representing the key</param>
/// <param name="value">The value to assign</param>
internal static void DoConversionsForSetInGenericDictionary ( IDictionary dictionary , ref object key , ref object value )
{
foreach ( Type i in dictionary . GetType (). GetInterfaces ())
{
TypeInfo typeInfo = i . GetTypeInfo ();
if ( typeInfo . IsGenericType && typeInfo . GetGenericTypeDefinition () == typeof ( IDictionary <,>))
{
// If we get here, we know the target implements IDictionary. We will assume
// that the non-generic implementation of the indexer property just forwards
// to the generic version, after checking the types of the key and value.
// This assumption holds for System.Collections.Generic.Dictionary<TKey,TValue>.
// If we did not make this assumption, we would be forced to generate code
// to call the generic indexer directly, somewhat analgous to what we do
// in GetEnumeratorFromIEnumeratorT.
Type [] genericArguments = i . GetGenericArguments ();
key = LanguagePrimitives . ConvertTo ( key , genericArguments [ 0 ], CultureInfo . InvariantCulture );
value = LanguagePrimitives . ConvertTo ( value , genericArguments [ 1 ], CultureInfo . InvariantCulture );
}
}
}
#region type converter
static internal PSTraceSource typeConversion = PSTraceSource . GetTracer ( "TypeConversion" , "Traces the type conversion algorithm" , false );
private static TypeConverter GetIntegerSystemConverter ( Type type )
{
if ( type == typeof ( Int16 ))
{
return new Int16Converter ();
}
else if ( type == typeof ( Int32 ))
{
return new Int32Converter ();
}
else if ( type == typeof ( Int64 ))
{
return new Int64Converter ();
}
else if ( type == typeof ( UInt16 ))
{
return new UInt16Converter ();
}
else if ( type == typeof ( UInt32 ))
{
return new UInt32Converter ();
}
else if ( type == typeof ( UInt64 ))
{
return new UInt64Converter ();
}
else if ( type == typeof ( Byte ))
{
return new ByteConverter ();
}
else if ( type == typeof ( SByte ))
{
return new SByteConverter ();
}
return null ;
}
/// backupTypeTable:
/// Used by Remoting Rehydration Logic. While Deserializing a remote object,
/// LocalPipeline.ExecutionContextFromTLS() might return null..In which case this
/// TypeTable will be used to do the conversion.
internal static object GetConverter ( Type type , TypeTable backupTypeTable )
{
object typesXmlConverter = null ;
ExecutionContext ecFromTLS = LocalPipeline . GetExecutionContextFromTLS ();
if ( ecFromTLS != null )
{
tracer . WriteLine ( "ecFromTLS != null" );
typesXmlConverter = ecFromTLS . TypeTable . GetTypeConverter ( type . FullName );
}
if (( typesXmlConverter == null ) && ( backupTypeTable != null ))
{
tracer . WriteLine ( "Using provided TypeTable to get the type converter" );
typesXmlConverter = backupTypeTable . GetTypeConverter ( type . FullName );
}
if ( typesXmlConverter != null )
{
tracer . WriteLine ( "typesXmlConverter != null" );
return typesXmlConverter ;
}
var typeConverters = type . GetTypeInfo (). GetCustomAttributes ( typeof ( TypeConverterAttribute ), false );
foreach ( var typeConverter in typeConverters )
{
var attr = ( TypeConverterAttribute ) typeConverter ;
string assemblyQualifiedtypeName = attr . ConverterTypeName ;
typeConversion . WriteLine ( "{0}'s TypeConverterAttribute points to {1}." , type , assemblyQualifiedtypeName );
// The return statement makes sure we only process the first TypeConverterAttribute
return NewConverterInstance ( assemblyQualifiedtypeName );
}
return null ;
}
private static object NewConverterInstance ( string assemblyQualifiedTypeName )
{
int typeSeparator = assemblyQualifiedTypeName . IndexOf ( "," , StringComparison . Ordinal );
if ( typeSeparator == - 1 )
{
typeConversion . WriteLine ( "Type name \"{0}\" should be assembly qualified." , assemblyQualifiedTypeName );
return null ;
}
string assemblyName = assemblyQualifiedTypeName . Substring ( typeSeparator + 2 );
string typeName = assemblyQualifiedTypeName . Substring ( 0 , typeSeparator );
foreach ( Assembly assembly in ClrFacade . GetAssemblies ( typeName ))
{
if ( assembly . FullName == assemblyName )
{
Type converterType = null ;
try
{
converterType = assembly . GetType ( typeName , false , false );
}
catch ( ArgumentException e )
{
typeConversion . WriteLine ( "Assembly \"{0}\" threw an exception when retrieving the type \"{1}\": \"{2}\"." , assemblyName , typeName , e . Message );
return null ;
}
try
{
return Activator . CreateInstance ( converterType );
}
catch ( Exception e )
{
CommandProcessorBase . CheckForSevereException ( e );
TargetInvocationException inner = e as TargetInvocationException ;
string message = ( inner == null ) || ( inner . InnerException == null ) ? e . Message : inner . InnerException . Message ;
typeConversion . WriteLine ( "Creating an instance of type \"{0}\" caused an exception to be thrown: \"{1}\"" , assemblyQualifiedTypeName , message );
return null ;
}
}
}
typeConversion . WriteLine ( "Could not create an instance of type \"{0}\"." , assemblyQualifiedTypeName );
return null ;
}
/// <summary>
/// BUGBUG - brucepay Mar. 2013 - I don't think this is general enough for dynamic keywords to support arbitrary target
/// languages with arbitrary type representations so we may need an extension point here...
///
/// Maps a .NET or CIM type name string (e.g. SInt32) to the form expected by PowerShell users, namely "[typename]"
/// If there is no mapping, then it returns null.
/// If the string to convert is null or empty then the function returns "[object]" as the default typeless type.
/// </summary>
/// <param name="typeName">The typename string to convert.</param>
/// <returns>The equivalent PowerShell representatin of that type.</returns>
public static string ConvertTypeNameToPSTypeName ( string typeName )
{
if ( string . IsNullOrWhiteSpace ( typeName ))
{
return "[object]" ;
}
string mappedType ;
if ( nameMap . TryGetValue ( typeName , out mappedType ))
{
return ( '[' + mappedType + ']' );
}
// Then check dot net types
Type dotNetType ;
if ( TypeResolver . TryResolveType ( typeName , out dotNetType ))
{
// Pass through the canonicalize type name we get back from the type converter...
return '[' + LanguagePrimitives . ConvertTo < string >( dotNetType ) + ']' ;
}
// No mapping is found, return null
return null ;
}
//
// CIM name string to .NET namestring mapping table
// (Considered using the MI routines but they didn't do quite the right thing.
//
static Dictionary < string , string > nameMap = new Dictionary < string , string >( StringComparer . OrdinalIgnoreCase ) {
{ "SInt8" , "SByte" },
{ "UInt8" , "Byte" },
{ "SInt16" , "Int16" },
{ "UInt16" , "UInt16" },
{ "SInt32" , "Int32" },
{ "UInt32" , "UInt32" },
{ "SInt64" , "Int64" },
{ "UInt64" , "UInt64" },
{ "Real32" , "Single" },
{ "Real64" , "double" },
{ "Boolean" , "bool" },
{ "String" , "string" },
{ "DateTime" , "DateTime" },
{ "Reference" , "CimInstance" },
{ "Char16" , "char" },
{ "Instance" , "CimInstance" },
{ "BooleanArray" , "bool[]" },
{ "UInt8Array" , "byte[]" },
{ "SInt8Array" , "Sbyte[]" },
{ "UInt16Array" , "uint16[]" },
{ "SInt16Array" , "int64[]" },
{ "UInt32Array" , "UInt32[]" },
{ "SInt32Array" , "Int32[]" },
{ "UInt64Array" , "UInt64[]" },
{ "SInt64Array" , "Int64[]" },
{ "Real32Array" , "Single[]" },
{ "Real64Array" , "double[]" },
{ "Char16Array" , "char[]" },
{ "DateTimeArray" , "DateTime[]" },
{ "StringArray" , "string[]" },
{ "ReferenceArray" , "CimInstance[]" },
{ "InstanceArray" , "CimInstance[]" },
{ "Unknown" , "UnknownType" },
};
#region public type conversion
/// <summary>
/// Converts valueToConvert to resultType
/// </summary>
/// <remarks>
/// A null valueToConvert can be converted to :
/// string - returns ""
/// char - returns '\0'
/// numeric types - returns 0 converted to the appropriate type
/// boolean - returns LanguagePrimitives.IsTrue(null)
/// PSObject - returns new PSObject())
/// array - returns an array with null in array[0]
/// non value types - returns null
///
/// The following conversions are considered language standard and cannot be customized:
/// - from derived to base class - returns valueToConvert intact
/// - to PSObject - returns PSObject.AsPSObject(valueToConvert)
/// - to void - returns AutomationNull.Value
/// - from array/IEnumerable to array - tries to convert array/IEnumerable elements
/// - from object of type X to array of X - returns an array with object as its only element
/// - to bool - returns LanguagePrimitives.IsTrue(valueToConvert)
/// - to string - returns a string representation of the object.
/// In the particular case of a number to string,
/// the conversion is culture invariant.
/// - from IDictionary to Hashtable - uses the Hashtable constructor
/// - to XmlDocument - creates a new XmlDocument with the
/// string representation of valueToConvert
/// - from string to char[] - returns ((string)valueToConvert).ToCharArray()
/// - from string to RegEx - creates a new RegEx with the string
/// - from string to Type - looks up the type in the minishell's assemblies
/// - from empty string to numeric - returns 0 converted to the appropriate type
/// - from string to numeric - returns a culture invariant conversion
/// - from ScriptBlock to Delegate - returns a delegate wrapping that scriptblock.
/// - from Integer to Enumeration - Uses Enum.ToObject
/// - to WMI - Instantiate a WMI instance using
/// System.Management.ManagementObject
/// - to WMISearcher - returns objects from running WQL query with the
/// string representation of valueToConvert. The
/// query is run using ManagementObjectSearcher Class.
/// - to WMIClass - returns ManagementClass represented by the
/// string representation of valueToConvert.
/// - to ADSI - returns DirectoryEntry represented by the
/// string representation of valueToConvert.
/// - to ADSISearcher - return DirectorySearcher representd by the
/// string representation of valueToConvert.
///
/// If none of the cases above is true, the following is considered in order:
///
/// 1) TypeConverter and PSTypeConverter
/// 2) the Parse methods if the valueToConvert is a string
/// 3) Constructors in resultType that take one parameter with type valueToConvert.GetType()
/// 4) Implicit and explicit cast operators
/// 5) IConvertible
///
/// If any operation above throws an exception, this exception will be wrapped into a
/// PSInvalidCastException and thrown resulting in no further conversion attempt.
/// </remarks>
/// <param name="valueToConvert">value to be converted and returned</param>
/// <param name="resultType">type to convert valueToConvert</param>
/// <returns>converted value</returns>
/// <exception cref="ArgumentNullException">if resultType is null</exception>
/// <exception cref="PSInvalidCastException">if the conversion failed</exception>
public static object ConvertTo ( object valueToConvert , Type resultType )
{
return ConvertTo ( valueToConvert , resultType , true , CultureInfo . InvariantCulture , null );
}
/// <summary>
/// Converts valueToConvert to resultType possibly considering formatProvider
/// </summary>
/// <remarks>
/// A null valueToConvert can be converted to :
/// string - returns ""
/// char - returns '\0'
/// numeric types - returns 0 converted to the appropriate type
/// boolean - returns LanguagePrimitives.IsTrue(null)
/// PSObject - returns new PSObject())
/// array - returns an array with null in array[0]
/// non value types - returns null
///
/// The following conversions are considered language standard and cannot be customized:
/// - from derived to base class - returns valueToConvert intact
/// - to PSObject - returns PSObject.AsPSObject(valueToConvert)
/// - to void - returns AutomationNull.Value
/// - from array/IEnumerable to array - tries to convert array/IEnumerable elements
/// - from object of type X to array of X - returns an array with object as its only element
/// - to bool - returns LanguagePrimitives.IsTrue(valueToConvert)
/// - to string - returns a string representation of the object.
/// In the particular case of a number to string,
/// the conversion is culture invariant.
/// - from IDictionary to Hashtable - uses the Hashtable constructor
/// - to XmlDocument - creates a new XmlDocument with the
/// string representation of valueToConvert
/// - from string to char[] - returns ((string)valueToConvert).ToCharArray()
/// - from string to RegEx - creates a new RegEx with the string
/// - from string to Type - looks up the type in the minishell's assemblies
/// - from empty string to numeric - returns 0 converted to the appropriate type
/// - from string to numeric - returns a culture invariant conversion
/// - from ScriptBlock to Delegate - returns a delegate wrapping that scriptblock.
/// - from Integer to Enumeration - Uses Enum.ToObject
///
/// If none of the cases above is true, the following is considered in order:
///
/// 1) TypeConverter and PSTypeConverter
/// 2) the Parse methods if the valueToConvert is a string
/// 3) Constructors in resultType that take one parameter with type valueToConvert.GetType()
/// 4) Implicit and explicit cast operators
/// 5) IConvertible
///
/// If any operation above throws an exception, this exception will be wrapped into a
/// PSInvalidCastException and thrown resulting in no further conversion attempt.
/// </remarks>
/// <param name="valueToConvert">value to be converted and returned</param>
/// <param name="resultType">type to convert valueToConvert</param>
/// <param name="formatProvider">To be used in custom type conversions, to call parse and to call Convert.ChangeType</param>
/// <returns>converted value</returns>
/// <exception cref="ArgumentNullException">if resultType is null</exception>
/// <exception cref="PSInvalidCastException">if the conversion failed</exception>
public static object ConvertTo ( object valueToConvert , Type resultType , IFormatProvider formatProvider )
{
return ConvertTo ( valueToConvert , resultType , true , formatProvider , null );
}
/// <summary>
/// Converts PSObject to resultType.
/// </summary>
/// <param name="valueToConvert">value to be converted and returned.</param>
/// <param name="resultType">type to convert psobject.</param>
/// <param name="recursion">Indicates if inner properties have to be recursively converted.</param>
/// <param name="formatProvider">To be used in custom type conversions, to call parse and to call Convert.ChangeType</param>
/// <param name="ignoreUnknownMembers">Indiacates if Unknown members in the psobject have to be ignored if the corresponding members in resultType do not exist.</param>
/// <returns>converted value.</returns>
public static object ConvertPSObjectToType ( PSObject valueToConvert , Type resultType , bool recursion , IFormatProvider formatProvider , bool ignoreUnknownMembers )
{
if ( valueToConvert != null )
{
ConstructorInfo toConstructor = resultType . GetConstructor ( PSTypeExtensions . EmptyTypes );
ConvertViaNoArgumentConstructor noArgumentConstructorConverter = new ConvertViaNoArgumentConstructor ( toConstructor , resultType );
return noArgumentConstructorConverter . Convert ( PSObject . Base ( valueToConvert ), resultType , recursion , ( PSObject ) valueToConvert , formatProvider , null , ignoreUnknownMembers );
}
return null ;
}
/// <summary>
/// Generic convertto that simplifies workfing with workflow.
/// </summary>
/// <typeparam name="T">The type of object to return</typeparam>
/// <param name="valueToConvert"></param>
/// <returns></returns>
public static T ConvertTo < T >( object valueToConvert )
{
if ( valueToConvert is T )
{
return ( T ) valueToConvert ;
}
return ( T ) ConvertTo ( valueToConvert , typeof ( T ), true , CultureInfo . InvariantCulture , null );
}
/// <summary>
/// Sets result to valueToConvert converted to resultType.
/// </summary>
/// <remarks>
/// This method is a variant of ConvertTo that does not throw exceptions if the conversion fails.
/// </remarks>
/// <param name="valueToConvert">value to be converted and returned</param>
/// <param name="result">result of the conversion. This is valid only if the return is true.</param>
/// <returns>false for conversion failure, true for success</returns>
public static bool TryConvertTo < T >( object valueToConvert , out T result )
{
if ( valueToConvert is T )
{
result = ( T ) valueToConvert ;
return true ;
}
return TryConvertTo ( valueToConvert , CultureInfo . InvariantCulture , out result );
}
/// <summary>
/// Sets result to valueToConvert converted to resultType considering formatProvider
/// for custom conversions, calling the Parse method and calling Convert.ChangeType.
/// </summary>
/// <remarks>
/// This method is a variant of ConvertTo that does not throw exceptions if the conversion fails.
/// </remarks>
/// <param name="valueToConvert">value to be converted and returned</param>
/// <param name="formatProvider">governing conversion of types</param>
/// <param name="result">result of the conversion. This is valid only if the return is true.</param>
/// <returns>false for conversion failure, true for success</returns>
public static bool TryConvertTo < T >( object valueToConvert , IFormatProvider formatProvider , out T result )
{
result = default ( T );
try
{
result = ( T ) ConvertTo ( valueToConvert , typeof ( T ), formatProvider );
}
catch ( InvalidCastException )
{
return false ;
}
catch ( ArgumentException )
{
return false ;
}
return true ;
}
/// <summary>
/// Sets result to valueToConvert converted to resultType.
/// </summary>
/// <remarks>
/// This method is a variant of ConvertTo that does not throw exceptions if the conversion fails.
/// </remarks>
/// <param name="valueToConvert">value to be converted and returned</param>
/// <param name="resultType">type to convert valueToConvert</param>
/// <param name="result">result of the conversion. This is valid only if the return is true.</param>
/// <returns>false for conversion failure, true for success</returns>
public static bool TryConvertTo ( object valueToConvert , Type resultType , out object result )
{
return TryConvertTo ( valueToConvert , resultType , CultureInfo . InvariantCulture , out result );
}
/// <summary>
/// Sets result to valueToConvert converted to resultType considering formatProvider
/// for custom conversions, calling the Parse method and calling Convert.ChangeType.
/// </summary>
/// <remarks>
/// This method is a variant of ConvertTo that does not throw exceptions if the conversion fails.
/// </remarks>
/// <param name="valueToConvert">value to be converted and returned</param>
/// <param name="resultType">type to convert valueToConvert</param>
/// <param name="formatProvider">governing conversion of types</param>
/// <param name="result">result of the conversion. This is valid only if the return is true.</param>
/// <returns>false for conversion failure, true for success</returns>
public static bool TryConvertTo ( object valueToConvert , Type resultType , IFormatProvider formatProvider , out object result )
{
result = null ;
try
{
result = ConvertTo ( valueToConvert , resultType , formatProvider );
}
catch ( InvalidCastException )
{
return false ;
}
catch ( ArgumentException )
{
return false ;
}
return true ;
}
#endregion public type conversion
internal class EnumMultipleTypeConverter : EnumSingleTypeConverter
{
public override object ConvertFrom ( object sourceValue , Type destinationType , IFormatProvider formatProvider , bool ignoreCase )
{
return EnumSingleTypeConverter . BaseConvertFrom ( sourceValue , destinationType , formatProvider , ignoreCase , true );
}
}
internal class EnumSingleTypeConverter : PSTypeConverter
{
class EnumHashEntry
{
internal EnumHashEntry ( String [] names , Array values , UInt64 allValues , bool hasNegativeValue , bool hasFlagsAttribute )
{
this . names = names ;
this . values = values ;
this . allValues = allValues ;
this . hasNegativeValue = hasNegativeValue ;
this . hasFlagsAttribute = hasFlagsAttribute ;
}
internal String [] names ;
internal Array values ;
internal UInt64 allValues ;
internal bool hasNegativeValue ;
internal bool hasFlagsAttribute ;
}
// This static is thread safe based on the lock in GetEnumHashEntry
// It can be shared by Runspaces in different MiniShells
static readonly Dictionary < Type , EnumHashEntry > enumTable = new Dictionary < Type , EnumHashEntry >();
const int maxEnumTableSize = 100 ;
private static EnumHashEntry GetEnumHashEntry ( Type enumType )
{
lock ( enumTable )
{
EnumHashEntry returnValue ;
if ( enumTable . TryGetValue ( enumType , out returnValue ))
{
return returnValue ;
}
if ( enumTable . Count == maxEnumTableSize )
{
enumTable . Clear ();
}
UInt64 allValues = 0 ;
bool hasNegativeValue = false ;
Array values = Enum . GetValues ( enumType );
// Type.GetTypeCode will return the integer type code for enumType
if ( LanguagePrimitives . IsSignedInteger ( enumType . GetTypeCode ()))
{
foreach ( object value in values )
{
Int64 valueInt64 = Convert . ToInt64 ( value , CultureInfo . CurrentCulture );
// A negative value cannot be flag
if ( valueInt64 < 0 )
{
hasNegativeValue = true ;
break ;
}
// we know the value is not negative, so this conversion
// always succede
allValues |= Convert . ToUInt64 ( value , CultureInfo . CurrentCulture );
}
}
else
{
foreach ( object value in values )
{
allValues |= Convert . ToUInt64 ( value , CultureInfo . CurrentCulture );
}
}
// See if the [Flag] attribute is set on this type...
// MemberInfo.GetCustomAttributes returns IEnumerable<Attribute> in CoreCLR.
bool hasFlagsAttribute = enumType . GetTypeInfo (). GetCustomAttributes ( typeof ( FlagsAttribute ), false ). Any ();
returnValue = new EnumHashEntry ( Enum . GetNames ( enumType ), values , allValues , hasNegativeValue , hasFlagsAttribute );
enumTable . Add ( enumType , returnValue );
return returnValue ;
}
}
public override bool CanConvertFrom ( object sourceValue , Type destinationType )
{
return sourceValue is string && destinationType . GetTypeInfo (). IsEnum ;
}
/// <summary>
/// Checks if the enumValue is defined or not in enumType.
/// </summary>
/// <param name="enumType">some enumeration</param>
/// <param name="enumValue">supposed to be an integer</param>
/// <returns>
/// </returns>
private static bool IsDefinedEnum ( object enumValue , Type enumType )
{
bool isDefined ;
do
{
if ( enumValue == null )
{
isDefined = false ;
break ;
}
EnumHashEntry enumHashEntry = EnumSingleTypeConverter . GetEnumHashEntry ( enumType );
// An enumeration with a negative value should not be treated as flags
// so IsValueFlagDefined cannot determine the result, and as far as it knows,
// it is defined.
if ( enumHashEntry . hasNegativeValue )
{
isDefined = true ;
break ;
}
// Type.GetTypeCode will return the integer type code for enumValue.GetType()
if ( LanguagePrimitives . IsSignedInteger ( enumValue . GetType (). GetTypeCode ()))
{
Int64 enumValueInt64 = Convert . ToInt64 ( enumValue , CultureInfo . CurrentCulture );
// A negative value cannot be flag, so we return false
if ( enumValueInt64 < 0 )
{
isDefined = false ;
break ;
}
}
// the if above, guarantees that even if it is an Int64 it is > 0
// so the conversion should always work.
UInt64 enumValueUInt64 = Convert . ToUInt64 ( enumValue , CultureInfo . CurrentCulture );
if ( enumHashEntry . hasFlagsAttribute )
{
// This expression will result in a "1 bit" for bits that are
// set in enumValueInt64 but not set in enumHashEntry.allValues,
// and a "0 bit" otherwise. Any "bit 1" in the result, indicates this is not defined.
isDefined = (( enumValueUInt64 | enumHashEntry . allValues ) ^ enumHashEntry . allValues ) == 0 ;
}
else
{
// If flags is not set, then see if this value is in the list
// of valid values.
if ( Array . IndexOf ( enumHashEntry . values , enumValue ) >= 0 )
isDefined = true ;
else
isDefined = false ;
}
} while ( false );
return isDefined ;
}
/// <summary>
/// Throws if the enumType enumeration has no negative values, but the enumValue is not
/// defined in enumType.
/// </summary>
/// <param name="enumType">some enumeration</param>
/// <param name="enumValue">supposed to be an integer</param>
/// <param name="errorId">the error id to be used when throwing an exception</param>
internal static void ThrowForUndefinedEnum ( string errorId , object enumValue , Type enumType )
{
ThrowForUndefinedEnum ( errorId , enumValue , enumValue , enumType );
}
/// <summary>
/// Throws if the enumType enumeration has no negative values, but the enumValue is not
/// defined in enumType.
/// </summary>
/// <param name="errorId">The error id to be used when throwing an exception</param>
/// <param name="enumValue">value to validate</param>
/// <param name="valueToUseToThrow">value to use while throwing an exception</param>
/// <param name="enumType">the enum type to validate the enumValue with.</param>
/// <remarks>
/// <paramref name="valueToUseToThrow"/> is used by those callers who want the exception
/// to contain a different value than the one that is validated.
/// This will enable callers to take different forms of input -> convert to enum using
/// Enum.Object -> then validate using this method.
/// </remarks>
internal static void ThrowForUndefinedEnum ( string errorId , object enumValue , object valueToUseToThrow , Type enumType )
{
if (! IsDefinedEnum ( enumValue , enumType ))
{
typeConversion . WriteLine ( "Value {0} is not defined in the Enum {1}." , valueToUseToThrow , enumType );
throw new PSInvalidCastException ( errorId , null ,
ExtendedTypeSystem . InvalidCastExceptionEnumerationNoValue ,
valueToUseToThrow , enumType , EnumSingleTypeConverter . EnumValues ( enumType ));
}
}
internal static string EnumValues ( Type enumType )
{
EnumHashEntry enumHashEntry = EnumSingleTypeConverter . GetEnumHashEntry ( enumType );
return string . Join ( CultureInfo . CurrentUICulture . TextInfo . ListSeparator , enumHashEntry . names );
}
public override object ConvertFrom ( object sourceValue , Type destinationType , IFormatProvider formatProvider , bool ignoreCase )
{
return EnumSingleTypeConverter . BaseConvertFrom ( sourceValue , destinationType , formatProvider , ignoreCase , false );
}
protected static object BaseConvertFrom ( object sourceValue , Type destinationType , IFormatProvider formatProvider , bool ignoreCase , bool multipleValues )
{
Diagnostics . Assert ( sourceValue != null , "the type converter has a special case for null source values" );
string sourceValueString = sourceValue as string ;
if ( sourceValueString == null )
{
throw new PSInvalidCastException ( "InvalidCastEnumFromTypeNotAString" , null ,
ExtendedTypeSystem . InvalidCastException ,
sourceValue , ObjectToTypeNameString ( sourceValue ), destinationType );
}
Diagnostics . Assert ( destinationType . GetTypeInfo (). IsEnum , "EnumSingleTypeConverter is only applied to enumerations" );
if ( sourceValueString . Length == 0 )
{
throw new PSInvalidCastException ( "InvalidCastEnumFromEmptyString" , null ,
ExtendedTypeSystem . InvalidCastException ,
sourceValue , ObjectToTypeNameString ( sourceValue ), destinationType );
}
sourceValueString = sourceValueString . Trim ();
if ( sourceValueString . Length == 0 )
{
throw new PSInvalidCastException ( "InvalidEnumCastFromEmptyStringAfterTrim" , null ,
ExtendedTypeSystem . InvalidCastException ,
sourceValue , ObjectToTypeNameString ( sourceValue ), destinationType );
}
if ( Char . IsDigit ( sourceValueString [ 0 ]) || sourceValueString [ 0 ] == '+' || sourceValueString [ 0 ] == '-' )
{
Type underlyingType = Enum . GetUnderlyingType ( destinationType );
try
{
object result = Enum . ToObject ( destinationType , Convert . ChangeType ( sourceValueString , underlyingType , formatProvider ));
ThrowForUndefinedEnum ( "UndefinedInEnumSingleTypeConverter" , result , sourceValueString , destinationType );
return result ;
}
catch ( Exception e ) // Enum.ToObject and Convert.ChangeType might throw unadvertised exceptions
{
CommandProcessorBase . CheckForSevereException ( e );
// we still want to try non numeric match
}
}
string [] sourceValueEntries ;
WildcardPattern [] fromValuePatterns ;
if (! multipleValues )
{
if ( sourceValueString . Contains ( "," ))
{
throw new PSInvalidCastException ( "InvalidCastEnumCommaAndNoFlags" , null ,
ExtendedTypeSystem . InvalidCastExceptionEnumerationNoFlagAndComma ,
sourceValue , destinationType );
}
sourceValueEntries = new string [] { sourceValueString };
fromValuePatterns = new WildcardPattern [ 1 ];
if ( WildcardPattern . ContainsWildcardCharacters ( sourceValueString ))
{
fromValuePatterns [ 0 ] = WildcardPattern . Get ( sourceValueString , ignoreCase ? WildcardOptions . IgnoreCase : WildcardOptions . None );
}
else
{
fromValuePatterns [ 0 ] = null ;
}
}
else
{
sourceValueEntries = sourceValueString . Split ( Utils . Separators . Comma );
fromValuePatterns = new WildcardPattern [ sourceValueEntries . Length ];
for ( int i = 0 ; i < sourceValueEntries . Length ; i ++)
{
string sourceValueEntry = sourceValueEntries [ i ];
if ( WildcardPattern . ContainsWildcardCharacters ( sourceValueEntry ))
{
fromValuePatterns [ i ] = WildcardPattern . Get ( sourceValueEntry ,
ignoreCase ? WildcardOptions . IgnoreCase : WildcardOptions . None );
}
else
{
fromValuePatterns [ i ] = null ;
}
}
}
EnumHashEntry enumHashEntry = EnumSingleTypeConverter . GetEnumHashEntry ( destinationType );
string [] names = enumHashEntry . names ;
Array values = enumHashEntry . values ;
UInt64 returnUInt64 = 0 ;
StringComparison ignoreCaseOpt ;
if ( ignoreCase )
ignoreCaseOpt = StringComparison . OrdinalIgnoreCase ;
else
ignoreCaseOpt = StringComparison . Ordinal ;
for ( int i = 0 ; i < sourceValueEntries . Length ; i ++)
{
string sourceValueEntry = sourceValueEntries [ i ];
WildcardPattern fromValuePattern = fromValuePatterns [ i ];
bool foundOne = false ;
for ( int j = 0 ; j < names . Length ; j ++)
{
string name = names [ j ];
if ( fromValuePattern != null )
{
if (! fromValuePattern . IsMatch ( name ))
continue ;
}
else
{
if ( String . Compare ( sourceValueEntry , name , ignoreCaseOpt ) != 0 )
continue ;
}
if (! multipleValues && foundOne )
{
object firstValue = Enum . ToObject ( destinationType , returnUInt64 );
object secondValue = Enum . ToObject ( destinationType , Convert . ToUInt64 ( values . GetValue ( i ), CultureInfo . CurrentCulture ));
throw new PSInvalidCastException ( "InvalidCastEnumTwoStringsFoundAndNoFlags" , null ,
ExtendedTypeSystem . InvalidCastExceptionEnumerationMoreThanOneValue ,
sourceValue , destinationType , firstValue , secondValue );
}
foundOne = true ;
returnUInt64 |= Convert . ToUInt64 ( values . GetValue ( j ), CultureInfo . CurrentCulture );
}
if (! foundOne )
{
throw new PSInvalidCastException ( "InvalidCastEnumStringNotFound" , null ,
ExtendedTypeSystem . InvalidCastExceptionEnumerationNoValue ,
sourceValueEntry , destinationType , EnumSingleTypeConverter . EnumValues ( destinationType ));
}
}
return Enum . ToObject ( destinationType , returnUInt64 );
}
public override bool CanConvertTo ( object sourceValue , Type destinationType )
{
return false ;
}
public override object ConvertTo ( object sourceValue , Type destinationType , IFormatProvider formatProvider , bool ignoreCase )
{
throw PSTraceSource . NewNotSupportedException ();
}
}
/// <summary>
/// There might be many cast operators in a Type A that take Type A. Each operator will have a
/// different return type. Because of that we cannot call GetMethod since it would cause a
/// AmbiguousMatchException. This auxilliar method calls GetMember to find the right method
/// </summary>
/// <param name="methodName">Either op_Excplicit or op_Implicit, at the moment</param>
/// <param name="targetType">the type to look for an operator</param>
/// <param name="originalType">Type of the only parameter the operator method should have</param>
/// <param name="resultType">Return type of the operator method</param>
/// <returns>A cast operator method, or null if not found</returns>
private static MethodInfo FindCastOperator ( string methodName , Type targetType , Type originalType , Type resultType )
{
using ( typeConversion . TraceScope ( "Looking for \"{0}\" cast operator." , methodName ))
{
// Get multiple matched Public & Static methods
var methods = ClrFacade . GetMethods ( targetType , methodName );
foreach ( MethodInfo method in methods )
{
if (! resultType . IsAssignableFrom ( method . ReturnType ))
{
continue ;
}
System . Reflection . ParameterInfo [] parameters = method . GetParameters ();
if ( parameters . Length != 1 || ! parameters [ 0 ]. ParameterType . IsAssignableFrom ( originalType ))
{
continue ;
}
typeConversion . WriteLine ( "Found \"{0}\" cast operator in type {1}." , methodName , targetType . FullName );
return method ;
}
typeConversion . TraceScope ( "Cast operator for \"{0}\" not found." , methodName );
return null ;
}
}
private static object ConvertNumericThroughDouble ( object valueToConvert , Type resultType )
{
using ( typeConversion . TraceScope ( "Numeric Conversion through System.Double." ))
{
// Eventual exceptions here are caught by the caller
object intermediate = Convert . ChangeType ( valueToConvert , typeof ( double ),
System . Globalization . CultureInfo . InvariantCulture . NumberFormat );
return Convert . ChangeType ( intermediate , resultType ,
System . Globalization . CultureInfo . InvariantCulture . NumberFormat );
}
}
#if ! CORECLR
// No Following Types In CoreCLR
// ManagementObject
// ManagementObjectSearcher
// ManagementClass
// CommaDelimitedStringCollection
// DirectoryEntry
#region Converters_Not_Available_In_CorePS
private static ManagementObject ConvertToWMI ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Standard type conversion to a ManagementObject." );
string valueToConvertString ;
try
{
valueToConvertString = PSObject . ToString ( null , valueToConvert , "\n" , null , null , true , true );
}
catch ( ExtendedTypeSystemException e )
{
typeConversion . WriteLine ( "Exception converting value to string: {0}" , e . Message );
throw new PSInvalidCastException ( "InvalidCastGetStringToWMI" , e ,
ExtendedTypeSystem . InvalidCastExceptionNoStringForConversion ,
resultType . ToString (), e . Message );
}
try
{
ManagementObject wmiObject = new ManagementObject ( valueToConvertString );
// ManagementObject will not throw if path does not contain valid key
if ( wmiObject . SystemProperties [ "__CLASS" ] == null )
{
string message = StringUtil . Format ( ExtendedTypeSystem . InvalidWMIPath , valueToConvertString );
throw new PSInvalidCastException ( message );
}
return wmiObject ;
}
catch ( Exception wmiObjectException )
{
CommandProcessorBase . CheckForSevereException ( wmiObjectException );
typeConversion . WriteLine ( "Exception creating WMI object: \"{0}\"." , wmiObjectException . Message );
throw new PSInvalidCastException ( "InvalidCastToWMI" , wmiObjectException ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), wmiObjectException . Message );
}
}
private static ManagementObjectSearcher ConvertToWMISearcher ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Standard type conversion to a collection of ManagementObjects." );
string valueToConvertString ;
try
{
valueToConvertString = PSObject . ToString ( null , valueToConvert , "\n" , null , null , true , true );
}
catch ( ExtendedTypeSystemException e )
{
typeConversion . WriteLine ( "Exception converting value to string: {0}" , e . Message );
throw new PSInvalidCastException ( "InvalidCastGetStringToWMISearcher" , e ,
ExtendedTypeSystem . InvalidCastExceptionNoStringForConversion ,
resultType . ToString (), e . Message );
}
try
{
ManagementObjectSearcher objectSearcher = new ManagementObjectSearcher ( valueToConvertString );
return objectSearcher ;
}
catch ( Exception objectSearcherException )
{
CommandProcessorBase . CheckForSevereException ( objectSearcherException );
typeConversion . WriteLine ( "Exception running WMI object query: \"{0}\"." , objectSearcherException . Message );
throw new PSInvalidCastException ( "InvalidCastToWMISearcher" , objectSearcherException ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), objectSearcherException . Message );
}
}
private static ManagementClass ConvertToWMIClass ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Standard type conversion to a ManagementClass." );
string valueToConvertString ;
try
{
valueToConvertString = PSObject . ToString ( null , valueToConvert , "\n" , null , null , true , true );
}
catch ( ExtendedTypeSystemException e )
{
typeConversion . WriteLine ( "Exception converting value to string: {0}" , e . Message );
throw new PSInvalidCastException ( "InvalidCastGetStringToWMIClass" , e ,
ExtendedTypeSystem . InvalidCastExceptionNoStringForConversion ,
resultType . ToString (), e . Message );
}
try
{
ManagementClass wmiClass = new System . Management . ManagementClass ( valueToConvertString );
// ManagementClass will not throw if the path specified is not
// a valid class.
if ( wmiClass . SystemProperties [ "__CLASS" ] == null )
{
string message = StringUtil . Format ( ExtendedTypeSystem . InvalidWMIClassPath , valueToConvertString );
throw new PSInvalidCastException ( message );
}
return wmiClass ;
}
catch ( Exception wmiClassException )
{
CommandProcessorBase . CheckForSevereException ( wmiClassException );
typeConversion . WriteLine ( "Exception creating WMI class: \"{0}\"." , wmiClassException . Message );
throw new PSInvalidCastException ( "InvalidCastToWMIClass" , wmiClassException ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), wmiClassException . Message );
}
}
// System.Configuration.CommaDelimitedStringCollection is derived from the StringCollection class
private static System . Configuration . CommaDelimitedStringCollection ConvertToCommaDelimitedStringCollection ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Standard type conversion to a CommaDelimitedStringCollection." );
var commaDelimitedStringCollection = new System . Configuration . CommaDelimitedStringCollection ();
AddItemsToCollection ( valueToConvert , resultType , formatProvider , backupTable , commaDelimitedStringCollection );
return commaDelimitedStringCollection ;
}
private static DirectoryEntry ConvertToADSI ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Standard type conversion to DirectoryEntry." );
string valueToConvertString ;
try
{
valueToConvertString = PSObject . ToString ( null , valueToConvert , "\n" , null , null , true , true );
}
catch ( ExtendedTypeSystemException e )
{
typeConversion . WriteLine ( "Exception converting value to string: {0}" , e . Message );
throw new PSInvalidCastException ( "InvalidCastGetStringToADSIClass" , e ,
ExtendedTypeSystem . InvalidCastExceptionNoStringForConversion ,
resultType . ToString (), e . Message );
}
try
{
DirectoryEntry entry = new DirectoryEntry ( valueToConvertString );
return entry ;
}
catch ( Exception adsiClassException )
{
CommandProcessorBase . CheckForSevereException ( adsiClassException );
typeConversion . WriteLine ( "Exception creating ADSI class: \"{0}\"." , adsiClassException . Message );
throw new PSInvalidCastException ( "InvalidCastToADSIClass" , adsiClassException ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), adsiClassException . Message );
}
}
private static DirectorySearcher ConvertToADSISearcher ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Standard type conversion to ADSISearcher" );
try
{
return new DirectorySearcher (( string ) valueToConvert );
}
catch ( Exception e )
{
CommandProcessorBase . CheckForSevereException ( e );
typeConversion . WriteLine ( "Exception creating ADSI searcher: \"{0}\"." , e . Message );
throw new PSInvalidCastException ( "InvalidCastToADSISearcher" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
#endregion Converters_Not_Available_In_CorePS
#endif
private static StringCollection ConvertToStringCollection ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Standard type conversion to a StringCollection." );
var stringCollection = new StringCollection ();
AddItemsToCollection ( valueToConvert , resultType , formatProvider , backupTable , stringCollection );
return stringCollection ;
}
private static void AddItemsToCollection ( object valueToConvert , Type resultType , IFormatProvider formatProvider , TypeTable backupTable , StringCollection stringCollection )
{
try
{
var stringArrayValue = ( string []) ConvertTo ( valueToConvert , typeof ( string []), false , formatProvider , backupTable );
stringCollection . AddRange ( stringArrayValue );
}
catch ( PSInvalidCastException )
{
typeConversion . WriteLine ( "valueToConvert contains non-string type values" );
var argEx = new ArgumentException ( StringUtil . Format ( ExtendedTypeSystem . CannotConvertValueToStringArray , valueToConvert . ToString ()));
throw new PSInvalidCastException ( StringUtil . Format ( "InvalidCastTo{0}Class" , resultType . Name ), argEx ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException , valueToConvert . ToString (), resultType . ToString (), argEx . Message );
}
catch ( Exception ex )
{
CommandProcessorBase . CheckForSevereException ( ex );
typeConversion . WriteLine ( "Exception creating StringCollection class: \"{0}\"." , ex . Message );
throw new PSInvalidCastException ( StringUtil . Format ( "InvalidCastTo{0}Class" , resultType . Name ), ex ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException , valueToConvert . ToString (), resultType . ToString (), ex . Message );
}
}
private static XmlDocument ConvertToXml ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
using ( typeConversion . TraceScope ( "Standard type conversion to XmlDocument." ))
{
string valueToConvertString ;
try
{
valueToConvertString = PSObject . ToString ( null , valueToConvert , "\n" , null , null , true , true );
}
catch ( ExtendedTypeSystemException e )
{
typeConversion . WriteLine ( "Exception converting value to string: {0}" , e . Message );
throw new PSInvalidCastException ( "InvalidCastGetStringToXmlDocument" , e ,
ExtendedTypeSystem . InvalidCastExceptionNoStringForConversion ,
resultType . ToString (), e . Message );
}
try
{
using ( TextReader textReader = new StringReader ( valueToConvertString ))
{
// Win8: 481571 Enforcing "PreserveWhitespace" breaks XML pretty printing
XmlReaderSettings settings = InternalDeserializer . XmlReaderSettingsForUntrustedXmlDocument . Clone ();
settings . IgnoreWhitespace = true ;
settings . IgnoreProcessingInstructions = false ;
settings . IgnoreComments = false ;
XmlReader xmlReader = XmlReader . Create ( textReader , settings );
XmlDocument xmlDocument = new XmlDocument ();
xmlDocument . PreserveWhitespace = false ;
xmlDocument . Load ( xmlReader );
return xmlDocument ;
}
}
catch ( Exception loadXmlException )
{
typeConversion . WriteLine ( "Exception loading XML: \"{0}\"." , loadXmlException . Message );
CommandProcessorBase . CheckForSevereException ( loadXmlException );
throw new PSInvalidCastException ( "InvalidCastToXmlDocument" , loadXmlException ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), loadXmlException . Message );
}
}
}
private static CultureInfo GetCultureFromFormatProvider ( IFormatProvider formatProvider )
{
CultureInfo returnValue = formatProvider as CultureInfo ;
if ( returnValue == null )
{
returnValue = CultureInfo . InvariantCulture ;
}
return returnValue ;
}
/// backupTypeTable:
/// Used by Remoting Rehydration Logic. While Deserializing a remote object,
/// LocalPipeline.ExecutionCotextFromTLS() might return null..In which case this
/// TypeTable will be used to do the conversion.
private static bool IsCustomTypeConversion ( object valueToConvert ,
Type resultType ,
IFormatProvider formatProvider ,
out object result ,
TypeTable backupTypeTable )
{
using ( typeConversion . TraceScope ( "Custom type conversion." ))
{
object baseValueToConvert = PSObject . Base ( valueToConvert );
Type originalType = baseValueToConvert . GetType ();
// first using ConvertTo for the original type
object valueConverter = GetConverter ( originalType , backupTypeTable );
if (( valueConverter != null ))
{
TypeConverter valueTypeConverter = valueConverter as TypeConverter ;
if ( valueTypeConverter != null )
{
typeConversion . WriteLine ( "Original type's converter is TypeConverter." );
if ( valueTypeConverter . CanConvertTo ( resultType ))
{
typeConversion . WriteLine ( "TypeConverter can convert to resultType." );
try
{
result = valueTypeConverter . ConvertTo ( null , GetCultureFromFormatProvider ( formatProvider ), baseValueToConvert , resultType );
return true ;
}
catch ( Exception e )
{
typeConversion . WriteLine ( "Exception converting with Original type's TypeConverter: \"{0}\"." , e . Message );
CommandProcessorBase . CheckForSevereException ( e );
throw new PSInvalidCastException ( "InvalidCastTypeConvertersConvertTo" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
else
{
typeConversion . WriteLine ( "TypeConverter cannot convert to resultType." );
}
}
PSTypeConverter valuePSTypeConverter = valueConverter as PSTypeConverter ;
if ( valuePSTypeConverter != null )
{
typeConversion . WriteLine ( "Original type's converter is PSTypeConverter." );
PSObject psValueToConvert = PSObject . AsPSObject ( valueToConvert );
if ( valuePSTypeConverter . CanConvertTo ( psValueToConvert , resultType ))
{
typeConversion . WriteLine ( "Original type's PSTypeConverter can convert to resultType." );
try
{
result = valuePSTypeConverter . ConvertTo ( psValueToConvert , resultType , formatProvider , true );
return true ;
}
catch ( Exception e )
{
typeConversion . WriteLine ( "Exception converting with Original type's PSTypeConverter: \"{0}\"." , e . Message );
CommandProcessorBase . CheckForSevereException ( e );
throw new PSInvalidCastException ( "InvalidCastPSTypeConvertersConvertTo" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
else
{
typeConversion . WriteLine ( "Original type's PSTypeConverter cannot convert to resultType." );
}
}
}
tracer . WriteLine ( "No converter found in original type." );
// now ConvertFrom for the destination type
valueConverter = GetConverter ( resultType , backupTypeTable );
if ( valueConverter != null )
{
TypeConverter valueTypeConverter = valueConverter as TypeConverter ;
if ( valueTypeConverter != null )
{
typeConversion . WriteLine ( "Destination type's converter is TypeConverter that can convert from originalType." );
if ( valueTypeConverter . CanConvertFrom ( originalType ))
{
typeConversion . WriteLine ( "Destination type's converter can convert from originalType." );
try
{
result = valueTypeConverter . ConvertFrom ( null , GetCultureFromFormatProvider ( formatProvider ), baseValueToConvert );
return true ;
}
catch ( Exception e )
{
typeConversion . WriteLine ( "Exception converting with Destination type's TypeConverter: \"{0}\"." , e . Message );
CommandProcessorBase . CheckForSevereException ( e );
throw new PSInvalidCastException ( "InvalidCastTypeConvertersConvertFrom" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
else
{
typeConversion . WriteLine ( "Destination type's converter cannot convert from originalType." );
}
}
PSTypeConverter valuePSTypeConverter = valueConverter as PSTypeConverter ;
if ( valuePSTypeConverter != null )
{
typeConversion . WriteLine ( "Destination type's converter is PSTypeConverter." );
PSObject psValueToConvert = PSObject . AsPSObject ( valueToConvert );
if ( valuePSTypeConverter . CanConvertFrom ( psValueToConvert , resultType ))
{
typeConversion . WriteLine ( "Destination type's converter can convert from originalType." );
try
{
result = valuePSTypeConverter . ConvertFrom ( psValueToConvert , resultType , formatProvider , true );
return true ;
}
catch ( Exception e )
{
typeConversion . WriteLine ( "Exception converting with Destination type's PSTypeConverter: \"{0}\"." , e . Message );
CommandProcessorBase . CheckForSevereException ( e );
throw new PSInvalidCastException ( "InvalidCastPSTypeConvertersConvertFrom" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
else
{
typeConversion . WriteLine ( "Destination type's converter cannot convert from originalType." );
}
}
}
result = null ;
return false ;
}
}
static private object ConvertNumericChar ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
try
{
// Convert char through int to float/double.
object result = Convert . ChangeType (
Convert . ChangeType ( valueToConvert , typeof ( int ), formatProvider ), resultType , formatProvider );
typeConversion . WriteLine ( "Numeric conversion succeeded." );
return result ;
}
catch ( Exception e )
{
typeConversion . WriteLine ( "Exception converting with IConvertible: \"{0}\"." , e . Message );
CommandProcessorBase . CheckForSevereException ( e );
throw new PSInvalidCastException ( "InvalidCastIConvertible" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
static private object ConvertNumeric ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
try
{
object result = Convert . ChangeType ( valueToConvert , resultType , formatProvider );
typeConversion . WriteLine ( "Numeric conversion succeeded." );
return result ;
}
catch ( Exception e )
{
typeConversion . WriteLine ( "Exception converting with IConvertible: \"{0}\"." , e . Message );
CommandProcessorBase . CheckForSevereException ( e );
throw new PSInvalidCastException ( "InvalidCastIConvertible" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
static private char [] ConvertStringToCharArray ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
Diagnostics . Assert ( valueToConvert is string , "Value to convert must be string" );
typeConversion . WriteLine ( "Returning value to convert's ToCharArray()." );
// This conversion is not wrapped in a try/catch because it can't raise an exception
// unless the string object has been corrupted.
return (( string ) valueToConvert ). ToCharArray ();
}
static private Regex ConvertStringToRegex ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
Diagnostics . Assert ( valueToConvert is string , "Value to convert must be string" );
typeConversion . WriteLine ( "Returning new RegEx(value to convert)." );
try
{
return new Regex (( string ) valueToConvert );
}
catch ( Exception regexException )
{
typeConversion . WriteLine ( "Exception in RegEx constructor: \"{0}\"." , regexException . Message );
CommandProcessorBase . CheckForSevereException ( regexException );
throw new PSInvalidCastException ( "InvalidCastFromStringToRegex" , regexException ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), regexException . Message );
}
}
static private Microsoft . Management . Infrastructure . CimSession ConvertStringToCimSession ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
Diagnostics . Assert ( valueToConvert is string , "Value to convert must be string" );
typeConversion . WriteLine ( "Returning CimSession.Create(value to convert)." );
try
{
return Microsoft . Management . Infrastructure . CimSession . Create (( string ) valueToConvert );
}
catch ( Microsoft . Management . Infrastructure . CimException cimException )
{
typeConversion . WriteLine ( "Exception in CimSession.Create: \"{0}\"." , cimException . Message );
throw new PSInvalidCastException ( "InvalidCastFromStringToCimSession" , cimException ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), cimException . Message );
}
}
private static Type ConvertStringToType ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
Diagnostics . Assert ( valueToConvert is string , "Value to convert must be a string" );
Exception exception ;
Type namedType = TypeResolver . ResolveType (( string ) valueToConvert , out exception );
if ( namedType == null )
{
if ( exception is PSInvalidCastException )
{
throw exception ;
}
throw new PSInvalidCastException ( "InvalidCastFromStringToType" , exception ,
ExtendedTypeSystem . InvalidCastException ,
valueToConvert . ToString (), ObjectToTypeNameString ( valueToConvert ), resultType . ToString ());
}
return namedType ;
}
/// <summary>
/// We need to add this built-in converter because in FullCLR, Syste.Uri has a TypeConverter attribute
/// declared: [TypeConverter(typeof(UriTypeConverter))], so the conversion from 'string' to 'Uri' is
/// actually taken care of by 'UriTypeConverter'. However, the type 'UriTypeConverter' is not available
/// in CoreCLR, and thus the conversion from 'string' to 'Uri' would show a different behavior.
///
/// Therefore, we just add this built-in string-to-uri converter using the same logic 'UriTypeConverter'
/// is using in FullCLR, so the conversion behavior will be the same on desktop powershell and powershell core.
/// </summary>
private static Uri ConvertStringToUri ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
try
{
Diagnostics . Assert ( valueToConvert is string , "Value to convert must be a string" );
return new Uri (( string ) valueToConvert , UriKind . RelativeOrAbsolute );
}
catch ( Exception uriException )
{
typeConversion . WriteLine ( "Exception in Uri constructor: \"{0}\"." , uriException . Message );
CommandProcessorBase . CheckForSevereException ( uriException );
throw new PSInvalidCastException ( "InvalidCastFromStringToUri" , uriException ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), uriException . Message );
}
}
private static object ConvertStringToInteger ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
var strToConvert = valueToConvert as string ;
Diagnostics . Assert ( strToConvert != null , "Value to convert must be a string" );
Diagnostics . Assert ( IsNumeric ( GetTypeCode ( resultType )), "Result type must be numeric" );
if ( strToConvert . Length == 0 )
{
typeConversion . WriteLine ( "Returning numeric zero." );
// This is not wrapped in a try/catch because it can't fail.
return System . Convert . ChangeType ( 0 , resultType , CultureInfo . InvariantCulture );
}
typeConversion . WriteLine ( "Converting to integer." );
TypeConverter integerConverter = LanguagePrimitives . GetIntegerSystemConverter ( resultType );
try
{
return integerConverter . ConvertFrom ( strToConvert );
}
catch ( Exception e )
{
// This catch has one extra reason to be generic (Exception e).
// integerConverter.ConvertFrom warps its exceptions in a System.Exception.
CommandProcessorBase . CheckForSevereException ( e );
if ( e . InnerException != null )
{
e = e . InnerException ;
}
typeConversion . WriteLine ( "Exception converting to integer: \"{0}\"." , e . Message );
CommandProcessorBase . CheckForSevereException ( e );
if ( e is FormatException )
{
typeConversion . WriteLine ( "Converting to integer passing through double." );
try
{
return ConvertNumericThroughDouble ( strToConvert , resultType );
}
catch ( Exception ex ) // swallow non-severe exceptions
{
typeConversion . WriteLine ( "Exception converting to integer through double: \"{0}\"." , ex . Message );
CommandProcessorBase . CheckForSevereException ( ex );
}
}
throw new PSInvalidCastException ( "InvalidCastFromStringToInteger" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
strToConvert , resultType . ToString (), e . Message );
}
}
private static object ConvertStringToDecimal ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
Diagnostics . Assert ( valueToConvert is string , "Value to convert must be a string" );
if ((( string ) valueToConvert ). Length == 0 )
{
typeConversion . WriteLine ( "Returning numeric zero." );
// This is not wrapped in a try/catch because it can't fail.
return System . Convert . ChangeType ( 0 , resultType , CultureInfo . InvariantCulture );
}
typeConversion . WriteLine ( "Converting to decimal." );
try
{
return Convert . ChangeType ( valueToConvert , resultType ,
System . Globalization . CultureInfo . InvariantCulture . NumberFormat );
}
catch ( Exception e )
{
typeConversion . WriteLine ( "Exception converting to decimal: \"{0}\". Converting to decimal passing through double." , e . Message );
CommandProcessorBase . CheckForSevereException ( e );
if ( e is FormatException )
{
try
{
return ConvertNumericThroughDouble ( valueToConvert , resultType );
}
catch ( Exception ex )
{
typeConversion . WriteLine ( "Exception converting to integer through double: \"{0}\"." , ex . Message );
CommandProcessorBase . CheckForSevereException ( ex );
}
}
throw new PSInvalidCastException ( "InvalidCastFromStringToDecimal" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
private static object ConvertStringToReal ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
Diagnostics . Assert ( valueToConvert is string , "Value to convert must be a string" );
if ((( string ) valueToConvert ). Length == 0 )
{
typeConversion . WriteLine ( "Returning numeric zero." );
// This is not wrapped in a try/catch because it can't fail.
return System . Convert . ChangeType ( 0 , resultType , CultureInfo . InvariantCulture );
}
typeConversion . WriteLine ( "Converting to double or single." );
try
{
return Convert . ChangeType ( valueToConvert , resultType ,
System . Globalization . CultureInfo . InvariantCulture . NumberFormat );
}
catch ( Exception e )
{
typeConversion . WriteLine ( "Exception converting to double or single: \"{0}\"." , e . Message );
CommandProcessorBase . CheckForSevereException ( e );
throw new PSInvalidCastException ( "InvalidCastFromStringToDoubleOrSingle" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
private static object ConvertAssignableFrom ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Result type is assignable from value to convert's type" );
return valueToConvert ;
}
private static PSObject ConvertToPSObject ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Returning PSObject.AsPSObject(valueToConvert)." );
return PSObject . AsPSObject ( valueToConvert );
}
private static object ConvertToVoid ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "returning AutomationNull.Value." );
return AutomationNull . Value ;
}
private static bool ConvertClassToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Converting ref to boolean." );
return valueToConvert != null ;
}
private static bool ConvertValueToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Converting value to boolean." );
return true ;
}
private static bool ConvertStringToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Converting string to boolean." );
return LanguagePrimitives . IsTrue (( string ) valueToConvert );
}
private static bool ConvertInt16ToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
return (( Int16 ) valueToConvert ) != default ( Int16 );
}
private static bool ConvertInt32ToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
return (( Int32 ) valueToConvert ) != default ( Int32 );
}
private static bool ConvertInt64ToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
return (( Int64 ) valueToConvert ) != default ( Int64 );
}
private static bool ConvertUInt16ToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
return (( UInt16 ) valueToConvert ) != default ( UInt16 );
}
private static bool ConvertUInt32ToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
return (( UInt32 ) valueToConvert ) != default ( UInt32 );
}
private static bool ConvertUInt64ToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
return (( UInt64 ) valueToConvert ) != default ( UInt64 );
}
private static bool ConvertSByteToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
return (( SByte ) valueToConvert ) != default ( SByte );
}
private static bool ConvertByteToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
return (( Byte ) valueToConvert ) != default ( Byte );
}
private static bool ConvertSingleToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
return (( Single ) valueToConvert ) != default ( Single );
}
private static bool ConvertDoubleToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
return (( Double ) valueToConvert ) != default ( Double );
}
private static bool ConvertDecimalToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
return (( Decimal ) valueToConvert ) != default ( Decimal );
}
static PSConverter < bool > CreateNumericToBoolConverter ( Type fromType )
{
Diagnostics . Assert ( LanguagePrimitives . IsNumeric ( fromType . GetTypeCode ()), "Can only convert numeric types" );
var valueToConvert = Expression . Parameter ( typeof ( object ));
var parameters = new ParameterExpression []
{
valueToConvert ,
Expression . Parameter ( typeof ( Type )),
Expression . Parameter ( typeof ( bool )),
Expression . Parameter ( typeof ( PSObject )),
Expression . Parameter ( typeof ( IFormatProvider )),
Expression . Parameter ( typeof ( TypeTable ))
};
return Expression . Lambda < PSConverter < bool >>(
Expression . NotEqual ( Expression . Default ( fromType ), valueToConvert . Cast ( fromType )),
parameters ). Compile ();
}
private static bool ConvertCharToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Converting char to boolean." );
char c = ( char ) valueToConvert ;
return c != '\0' ;
}
private static bool ConvertSwitchParameterToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Converting SwitchParameter to boolean." );
return (( SwitchParameter ) valueToConvert ). ToBool ();
}
private static bool ConvertIListToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Converting IList to boolean." );
return IsTrue (( IList ) valueToConvert );
}
private static string ConvertNumericToString ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
if ( originalValueToConvert != null && originalValueToConvert . TokenText != null )
{
return originalValueToConvert . TokenText ;
}
typeConversion . WriteLine ( "Converting numeric to string." );
try
{
// Ignore formatProvider here, the conversion should be culture invariant.
return ( string ) Convert . ChangeType ( valueToConvert , resultType , CultureInfo . InvariantCulture . NumberFormat );
}
catch ( Exception e )
{
typeConversion . WriteLine ( "Converting numeric to string Exception: \"{0}\"." , e . Message );
CommandProcessorBase . CheckForSevereException ( e );
throw new PSInvalidCastException ( "InvalidCastFromNumericToString" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
private static string ConvertNonNumericToString ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
ExecutionContext ecFromTLS = LocalPipeline . GetExecutionContextFromTLS ();
try
{
typeConversion . WriteLine ( "Converting object to string." );
return PSObject . ToStringParser ( ecFromTLS , valueToConvert );
}
catch ( ExtendedTypeSystemException e )
{
typeConversion . WriteLine ( "Converting object to string Exception: \"{0}\"." , e . Message );
throw new PSInvalidCastException ( "InvalidCastFromAnyTypeToString" , e ,
ExtendedTypeSystem . InvalidCastCannotRetrieveString );
}
}
private static Hashtable ConvertIDictionaryToHashtable ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Converting to Hashtable." );
return new Hashtable ( valueToConvert as IDictionary );
}
private static PSReference ConvertToPSReference ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Converting to PSReference." );
Dbg . Assert ( valueToConvert != null , "[ref]$null cast should be handler earlier with a separate ConvertNullToPSReference method" );
return PSReference . CreateInstance ( valueToConvert , valueToConvert . GetType ());
}
private static Delegate ConvertScriptBlockToDelegate ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
Exception exception = null ;
try
{
return (( ScriptBlock ) valueToConvert ). GetDelegate ( resultType );
}
catch ( ArgumentNullException e )
{
exception = e ;
}
catch ( ArgumentException e )
{
exception = e ;
}
catch ( MissingMethodException e )
{
exception = e ;
}
catch ( MemberAccessException e )
{
exception = e ;
}
typeConversion . WriteLine ( "Converting script block to delegate Exception: \"{0}\"." , exception . Message );
throw new PSInvalidCastException ( "InvalidCastFromScriptBlockToDelegate" , exception ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), exception . Message );
}
private static object ConvertToNullable ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
// The CLR doesn't support boxed Nullable<T>. Instead, languages convert to T and box.
return ConvertTo ( valueToConvert , Nullable . GetUnderlyingType ( resultType ), recursion , formatProvider , backupTable );
}
private static object ConvertRelatedArrays ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "The element type of result is assignable from the element type of the value to convert" );
var originalAsArray = ( Array ) valueToConvert ;
var newValue = Array . CreateInstance ( resultType . GetElementType (), originalAsArray . Length );
originalAsArray . CopyTo ( newValue , 0 );
return newValue ;
}
private static object ConvertUnrelatedArrays ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
Array valueAsArray = valueToConvert as Array ;
Type resultElementType = resultType . GetElementType ();
Array resultArray = Array . CreateInstance ( resultElementType , valueAsArray . Length );
for ( int i = 0 ; i < valueAsArray . Length ; i ++)
{
object resultElement = ConvertTo ( valueAsArray . GetValue ( i ), resultElementType , false , formatProvider , backupTable );
resultArray . SetValue ( resultElement , i );
}
return resultArray ;
}
private static object ConvertEnumerableToArray ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
try
{
ArrayList result = new ArrayList ();
Type resultElementType = resultType == typeof ( Array ) ? typeof ( object ) : resultType . GetElementType ();
typeConversion . WriteLine ( "Converting elements in the value to convert to the result's element type." );
foreach ( object obj in LanguagePrimitives . GetEnumerable ( valueToConvert ))
{
// false means no further recursions and therefore no cycles
result . Add ( ConvertTo ( obj , resultElementType , false , formatProvider , backupTable ));
}
return result . ToArray ( resultElementType );
}
catch ( Exception e )
{
typeConversion . WriteLine ( "Element conversion exception: \"{0}\"." , e . Message );
CommandProcessorBase . CheckForSevereException ( e );
throw new PSInvalidCastException ( "InvalidCastExceptionEnumerableToArray" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
private static object ConvertScalarToArray ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Value to convert is scalar." );
if ( originalValueToConvert != null && originalValueToConvert . TokenText != null )
{
valueToConvert = originalValueToConvert ;
}
try
{
Type resultElementType = resultType == typeof ( Array ) ? typeof ( object ) : resultType . GetElementType ();
ArrayList result = new ArrayList ();
// false means no further recursions and therefore no cycles
result . Add ( ConvertTo ( valueToConvert , resultElementType , false , formatProvider , backupTable ));
return result . ToArray ( resultElementType );
}
catch ( Exception e )
{
typeConversion . WriteLine ( "Element conversion exception: \"{0}\"." , e . Message );
CommandProcessorBase . CheckForSevereException ( e );
throw new PSInvalidCastException ( "InvalidCastExceptionScalarToArray" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
private static object ConvertIntegerToEnum ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
object result ;
try
{
result = System . Enum . ToObject ( resultType , valueToConvert );
}
catch ( Exception e )
{
typeConversion . WriteLine ( "Integer to System.Enum exception: \"{0}\"." , e . Message );
CommandProcessorBase . CheckForSevereException ( e );
throw new PSInvalidCastException ( "InvalidCastExceptionIntegerToEnum" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
// Check if the result is a defined enum..otherwise throw an error
// valueToConvert is the user supplied value. Use that in the error message.
EnumSingleTypeConverter . ThrowForUndefinedEnum ( "UndefinedIntegerToEnum" , result , valueToConvert , resultType );
return result ;
}
private static object ConvertStringToEnum ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
string valueAsString = valueToConvert as string ;
object result = null ;
typeConversion . WriteLine ( "Calling case sensitive Enum.Parse" );
try
{
result = Enum . Parse ( resultType , valueAsString );
}
catch ( ArgumentException e )
{
typeConversion . WriteLine ( "Enum.Parse Exception: \"{0}\"." , e . Message );
// Enum.Parse will always throw this kind of exception.
// Even when no map exists. We want to try without case sensitivity
// If it works, we will return it, otherwise a new exception will
// be thrown and we will use it to set exceptionToWrap
try
{
typeConversion . WriteLine ( "Calling case insensitive Enum.Parse" );
result = Enum . Parse ( resultType , valueAsString , true );
}
catch ( ArgumentException inner )
{
typeConversion . WriteLine ( "Enum.Parse Exception: \"{0}\"." , inner . Message );
}
catch ( Exception ex ) // Enum.Parse might throw unadvertised exceptions
{
CommandProcessorBase . CheckForSevereException ( ex );
typeConversion . WriteLine ( "Case insensitive Enum.Parse threw an exception." );
throw new PSInvalidCastException ( "CaseInsensitiveEnumParseThrewAnException" , ex ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), ex . Message );
}
}
catch ( Exception e ) // Enum.Parse might throw unadvertised exceptions
{
CommandProcessorBase . CheckForSevereException ( e );
typeConversion . WriteLine ( "Case Sensitive Enum.Parse threw an exception." );
throw new PSInvalidCastException ( "CaseSensitiveEnumParseThrewAnException" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
if ( result == null )
{
typeConversion . WriteLine ( "Calling substring disambiguation." );
try
{
string enumValue = EnumMinimumDisambiguation . EnumDisambiguate ( valueAsString , resultType );
result = Enum . Parse ( resultType , enumValue );
}
catch ( Exception e ) // Wrap exceptions in type conversion exceptions
{
CommandProcessorBase . CheckForSevereException ( e );
typeConversion . WriteLine ( "Substring disambiguation threw an exception." );
throw new PSInvalidCastException ( "SubstringDisambiguationEnumParseThrewAnException" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
EnumSingleTypeConverter . ThrowForUndefinedEnum ( "EnumParseUndefined" , result , valueToConvert , resultType );
tracer . WriteLine ( "returning \"{0}\" from conversion to Enum." , result );
return result ;
}
private static object ConvertEnumerableToEnum ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
IEnumerator e = LanguagePrimitives . GetEnumerator ( valueToConvert );
StringBuilder sbResult = new StringBuilder ();
bool notFirst = false ;
while ( ParserOps . MoveNext ( null , null , e ))
{
if ( notFirst )
sbResult . Append ( ',' );
else
notFirst = true ;
string current = e . Current as string ;
if ( current == null )
{
// If the object wasn't a string, then we'll try and convert it into an enum value,
// then convert the enum back to a string and finally append it to the string builder to
// preserve consistent semantics between quoted and unquoted lists...
object tempResult = ConvertTo ( e . Current , resultType , recursion , formatProvider , backupTable );
if ( tempResult != null )
{
sbResult . Append ( tempResult . ToString ());
}
else
{
throw new PSInvalidCastException ( "InvalidCastEnumStringNotFound" , null ,
ExtendedTypeSystem . InvalidCastExceptionEnumerationNoValue ,
e . Current , resultType , EnumSingleTypeConverter . EnumValues ( resultType ));
}
}
sbResult . Append ( current );
}
return ConvertStringToEnum ( sbResult . ToString (), resultType , recursion , originalValueToConvert , formatProvider , backupTable );
}
private class ConvertViaParseMethod
{
// TODO - use an ETS wrapper that generates a dynamic method
internal MethodInfo parse ;
internal object ConvertWithCulture ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
try
{
object result = parse . Invoke ( null , new object [ 2 ] { valueToConvert , formatProvider });
typeConversion . WriteLine ( "Parse result: {0}" , result );
return result ;
}
catch ( TargetInvocationException ex )
{
Exception inner = ex . InnerException ?? ex ;
typeConversion . WriteLine ( "Exception calling Parse method with CultureInfo: \"{0}\"." , inner . Message );
throw new PSInvalidCastException ( "InvalidCastParseTargetInvocationWithFormatProvider" , inner ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), inner . Message );
}
catch ( Exception e )
{
CommandProcessorBase . CheckForSevereException ( e );
typeConversion . WriteLine ( "Exception calling Parse method with CultureInfo: \"{0}\"." , e . Message );
throw new PSInvalidCastException ( "InvalidCastParseExceptionWithFormatProvider" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
internal object ConvertWithoutCulture ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
try
{
object result = parse . Invoke ( null , new object [ 1 ] { valueToConvert });
typeConversion . WriteLine ( "Parse result: \"{0}\"." , result );
return result ;
}
catch ( TargetInvocationException ex )
{
Exception inner = ex . InnerException ?? ex ;
typeConversion . WriteLine ( "Exception calling Parse method: \"{0}\"." , inner . Message );
throw new PSInvalidCastException ( "InvalidCastParseTargetInvocation" , inner ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), inner . Message );
}
catch ( Exception e )
{
CommandProcessorBase . CheckForSevereException ( e );
typeConversion . WriteLine ( "Exception calling Parse method: \"{0}\"." , e . Message );
throw new PSInvalidCastException ( "InvalidCastParseException" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
}
private class ConvertViaConstructor
{
internal Func < object , object > TargetCtorLambda ;
internal object Convert ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
try
{
object result = TargetCtorLambda ( valueToConvert );
typeConversion . WriteLine ( "Constructor result: \"{0}\"." , result );
return result ;
}
catch ( TargetInvocationException ex )
{
Exception inner = ex . InnerException ?? ex ;
typeConversion . WriteLine ( "Exception invoking Constructor: \"{0}\"." , inner . Message );
throw new PSInvalidCastException ( "InvalidCastConstructorTargetInvocationException" , inner ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), inner . Message );
}
catch ( Exception e )
{
CommandProcessorBase . CheckForSevereException ( e );
typeConversion . WriteLine ( "Exception invoking Constructor: \"{0}\"." , e . Message );
throw new PSInvalidCastException ( "InvalidCastConstructorException" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
}
/// <summary>
/// Create a IList to hold all elements, and use the IList to create the object of the resultType.
/// The reason for using IList is that it can work on constructors that takes IEnumerable[T], ICollection[T] or IList[T].
/// </summary>
/// <remark>
/// When get to this method, we know the fromType and the toType meet the following two conditions:
/// 1. toType is a closed generic type and it has a constructor that takes IEnumerable[T], ICollection[T] or IList[T]
/// 2. fromType is System.Array, System.Object[] or it's the same as the element type of toType
/// </remark>
private class ConvertViaIEnumerableConstructor
{
internal Func < int , IList > ListCtorLambda ;
internal Func < IList , object > TargetCtorLambda ;
internal Type ElementType ;
internal bool IsScalar ;
internal object Convert ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
IList resultAsList = null ;
int listSize = 0 ;
Array array = null ;
try
{
// typeof(Array).IsAssignableFrom(typeof(object[])) == true
if (( IsScalar ) || (!( valueToConvert is Array )))
{
listSize = 1 ;
}
else
{
array = ( Array ) valueToConvert ;
listSize = array . Length ;
}
resultAsList = ListCtorLambda ( listSize );
}
catch ( Exception e )
{
CommandProcessorBase . CheckForSevereException ( e );
ThrowInvalidCastException ( valueToConvert , resultType );
Diagnostics . Assert ( false , "ThrowInvalidCastException always throws" );
return null ;
}
if ( IsScalar )
{
resultAsList . Add ( valueToConvert );
}
else if ( listSize == 1 )
{
object convertedValue = LanguagePrimitives . ConvertTo ( valueToConvert , ElementType , formatProvider );
resultAsList . Add ( convertedValue );
}
else
{
foreach ( object item in array )
{
object baseObj = PSObject . Base ( item );
object convertedValue ;
if (! LanguagePrimitives . TryConvertTo ( baseObj , ElementType , formatProvider , out convertedValue ))
{
ThrowInvalidCastException ( valueToConvert , resultType );
Diagnostics . Assert ( false , "ThrowInvalidCastException always throws" );
return null ;
}
else
{
resultAsList . Add ( convertedValue );
}
}
}
try
{
object result = TargetCtorLambda ( resultAsList );
typeConversion . WriteLine ( "IEnumerable Constructor result: \"{0}\"." , result );
return result ;
}
catch ( TargetInvocationException ex )
{
Exception inner = ex . InnerException ?? ex ;
typeConversion . WriteLine ( "Exception invoking IEnumerable Constructor: \"{0}\"." , inner . Message );
throw new PSInvalidCastException ( "InvalidCastConstructorTargetInvocationException" , inner ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), inner . Message );
}
catch ( Exception e )
{
CommandProcessorBase . CheckForSevereException ( e );
typeConversion . WriteLine ( "Exception invoking IEnumerable Constructor: \"{0}\"." , e . Message );
throw new PSInvalidCastException ( "InvalidCastConstructorException" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
}
private class ConvertViaNoArgumentConstructor
{
private readonly Func < object > constructor ;
internal ConvertViaNoArgumentConstructor ( ConstructorInfo constructor , Type type )
{
var newExpr = ( constructor != null ) ? Expression . New ( constructor ) : Expression . New ( type );
this . constructor = Expression . Lambda < Func < object >>( newExpr . Cast ( typeof ( object ))). Compile ();
}
internal object Convert ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
return Convert ( valueToConvert , resultType , recursion , originalValueToConvert , formatProvider , backupTable , false );
}
internal object Convert ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable , bool ignoreUnknownMembers )
{
try
{
ExecutionContext ecFromTLS = LocalPipeline . GetExecutionContextFromTLS ();
object result = null ;
if (( ecFromTLS == null ) || ( ecFromTLS != null && ecFromTLS . LanguageMode == PSLanguageMode . FullLanguage ))
{
result = constructor ();
var psobject = valueToConvert as PSObject ;
if ( psobject != null )
{
// Use PSObject properties to perform conversion.
SetObjectProperties ( result , psobject , resultType , CreateMemberNotFoundError , CreateMemberSetValueError , formatProvider , recursion , ignoreUnknownMembers );
}
else
{
// Use provided property dictionary to perform conversion.
// The method invocation is disabled for "Hashtable to Object conversion" (Win8:649519), but we need to keep it enabled for New-Object for compatibility to PSv2
IDictionary properties = valueToConvert as IDictionary ;
SetObjectProperties ( result , properties , resultType , CreateMemberNotFoundError , CreateMemberSetValueError , enableMethodCall : false );
}
typeConversion . WriteLine ( "Constructor result: \"{0}\"." , result );
}
else
{
RuntimeException rte = InterpreterError . NewInterpreterException ( valueToConvert , typeof ( RuntimeException ), null ,
"HashtableToObjectConversionNotSupportedInDataSection" , ParserStrings . HashtableToObjectConversionNotSupportedInDataSection , resultType . ToString ());
throw rte ;
}
return result ;
}
catch ( TargetInvocationException ex )
{
Exception inner = ex . InnerException ?? ex ;
typeConversion . WriteLine ( "Exception invoking Constructor: \"{0}\"." , inner . Message );
throw new PSInvalidCastException ( "InvalidCastConstructorTargetInvocationException" , inner ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), inner . Message );
}
catch ( InvalidOperationException e )
{
Exception inner = e . InnerException ?? e ;
throw new PSInvalidCastException ( "ObjectCreationError" , e ,
ExtendedTypeSystem . ObjectCreationError , resultType . ToString (), inner . Message );
}
catch ( SetValueException e )
{
Exception inner = e . InnerException ?? e ;
throw new PSInvalidCastException ( "ObjectCreationError" , inner ,
ExtendedTypeSystem . ObjectCreationError , resultType . ToString (), inner . Message );
}
catch ( RuntimeException ex )
{
Exception inner = ex . InnerException ?? ex ;
typeConversion . WriteLine ( "Exception invoking Constructor: \"{0}\"." , inner . Message );
throw new PSInvalidCastException ( "InvalidCastConstructorException" , inner ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), inner . Message );
}
catch ( Exception e )
{
CommandProcessorBase . CheckForSevereException ( e );
typeConversion . WriteLine ( "Exception invoking Constructor: \"{0}\"." , e . Message );
throw new PSInvalidCastException ( "InvalidCastConstructorException" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
}
private class ConvertViaCast
{
internal MethodInfo cast ;
internal object Convert ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
try
{
return cast . Invoke ( null , new object [ 1 ] { valueToConvert });
}
catch ( TargetInvocationException ex )
{
Exception inner = ex . InnerException ?? ex ;
typeConversion . WriteLine ( "Cast operator exception: \"{0}\"." , inner . Message );
throw new PSInvalidCastException ( "InvalidCastTargetInvocationException" + cast . Name , inner ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), inner . Message );
}
catch ( Exception e )
{
CommandProcessorBase . CheckForSevereException ( e );
typeConversion . WriteLine ( "Cast operator exception: \"{0}\"." , e . Message );
throw new PSInvalidCastException ( "InvalidCastException" + cast . Name , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
}
private static object ConvertIConvertible ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
try
{
object result = Convert . ChangeType ( valueToConvert , resultType , formatProvider );
typeConversion . WriteLine ( "Conversion using IConvertible succeeded." );
return result ;
}
catch ( Exception e )
{
typeConversion . WriteLine ( "Exception converting with IConvertible: \"{0}\"." , e . Message );
CommandProcessorBase . CheckForSevereException ( e );
throw new PSInvalidCastException ( "InvalidCastIConvertible" , e ,
ExtendedTypeSystem . InvalidCastExceptionWithInnerException ,
valueToConvert . ToString (), resultType . ToString (), e . Message );
}
}
private static object ConvertNumericIConvertible ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
// If the original object was a number, then try and do a conversion on the string
// equivalent of that number...
if ( originalValueToConvert != null && originalValueToConvert . TokenText != null )
{
return LanguagePrimitives . ConvertTo ( originalValueToConvert . TokenText ,
resultType , recursion , formatProvider , backupTable );
}
else
{
// Convert the source object to a string...
string s = ( string ) LanguagePrimitives . ConvertTo ( valueToConvert ,
typeof ( string ), recursion , formatProvider , backupTable );
// And try and convert that string to the target type...
return LanguagePrimitives . ConvertTo ( s ,
resultType , recursion , formatProvider , backupTable );
}
}
private class ConvertCheckingForCustomConverter
{
internal PSConverter < object > tryfirstConverter ;
internal PSConverter < object > fallbackConverter ;
internal object Convert ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
object result = null ;
if ( tryfirstConverter != null )
{
try
{
return tryfirstConverter ( valueToConvert , resultType , recursion , originalValueToConvert , formatProvider , backupTable );
}
catch ( InvalidCastException )
{
}
}
if ( IsCustomTypeConversion ( originalValueToConvert ?? valueToConvert , resultType , formatProvider , out result , backupTable ))
{
typeConversion . WriteLine ( "Custom Type Conversion succeeded." );
return result ;
}
if ( fallbackConverter != null )
{
return fallbackConverter ( valueToConvert , resultType , recursion , originalValueToConvert , formatProvider , backupTable );
}
throw new PSInvalidCastException ( "ConvertToFinalInvalidCastException" , null ,
ExtendedTypeSystem . InvalidCastException ,
valueToConvert . ToString (), ObjectToTypeNameString ( valueToConvert ), resultType . ToString ());
}
}
#region Delegates converting null
private static object ConvertNullToNumeric ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Converting null to zero." );
// If the destination type is numeric, convert 0 to resultType
return System . Convert . ChangeType ( 0 , resultType , CultureInfo . InvariantCulture );
}
private static char ConvertNullToChar ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Converting null to '0'." );
return '\0' ;
}
private static string ConvertNullToString ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Converting null to \"\"." );
// if the destination type is string, return an empty string...
return String . Empty ;
}
private static PSReference ConvertNullToPSReference ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
return new PSReference < Null >( null );
}
private static object ConvertNullToRef ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
// if the target type is not a value type, return the original
// "null" object. Don't just return null because we want to preserve
// an msh object if possible.
return valueToConvert ;
}
private static bool ConvertNullToBool ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Converting null to boolean." );
return false ;
}
private static object ConvertNullToNullable ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
return null ;
}
private static SwitchParameter ConvertNullToSwitch ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Converting null to SwitchParameter(false)." );
return new SwitchParameter ( false );
}
private static object ConvertNullToVoid ( object valueToConvert ,
Type resultType ,
bool recursion ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
typeConversion . WriteLine ( "Converting null to AutomationNull.Value." );
return AutomationNull . Value ;
}
#endregion Delegates converting null
private static object ConvertNoConversion ( object valueToConvert ,
Type resultType ,
bool recurse ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
ThrowInvalidCastException ( valueToConvert , resultType );
Diagnostics . Assert ( false , "ThrowInvalidCastException always throws" );
return null ;
}
private static object ConvertNotSupportedConversion ( object valueToConvert ,
Type resultType ,
bool recurse ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable )
{
ThrowInvalidConversionException ( valueToConvert , resultType );
Diagnostics . Assert ( false , "ThrowInvalidCastException always throws" );
return null ;
}
private struct ConversionTypePair
{
internal Type from ;
internal Type to ;
internal ConversionTypePair ( Type fromType , Type toType )
{
from = fromType ;
to = toType ;
}
public override int GetHashCode ()
{
unchecked
{
// To prevent to/from == from/to, multiply and add rather than use
// an operation that won't overflow, like bitwise xor.
return from . GetHashCode () + 37 * to . GetHashCode ();
}
}
public override bool Equals ( object other )
{
if (!( other is ConversionTypePair ))
return false ;
var ctp = ( ConversionTypePair ) other ;
return this . from == ctp . from && this . to == ctp . to ;
}
}
internal delegate T PSConverter < T >( object valueToConvert ,
Type resultType ,
bool recurse ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable );
internal delegate object PSNullConverter ( object nullOrAutomationNull );
internal interface ConversionData
{
object Converter { get ; }
ConversionRank Rank { get ; }
object Invoke ( object valueToConvert ,
Type resultType ,
bool recurse ,
PSObject originalValueToConvert ,
IFormatProvider formatProvider ,
TypeTable backupTable );
}
internal class ConversionData < T > : ConversionData
{
private readonly PSConverter < T > converter ;
private readonly ConversionRank rank ;
public ConversionData ( PSConverter < T > converter , ConversionRank rank )
{
this . converter = converter ;
this . rank = rank ;
}
public object Converter
{
get { return converter ; }
}
public ConversionRank Rank
{
get { return rank ; }
}
public object Invoke ( object valueToConvert , Type resultType , bool recurse , PSObject originalValueToConvert , IFormatProvider formatProvider , TypeTable backupTable )
{
return converter . Invoke ( valueToConvert , resultType , recurse , originalValueToConvert , formatProvider , backupTable );
}
}
static Dictionary < ConversionTypePair , ConversionData > converterCache
= new Dictionary < ConversionTypePair , ConversionData >( 256 );
private static ConversionData CacheConversion < T >( Type fromType , Type toType , PSConverter < T > converter , ConversionRank rank )
{
ConversionTypePair pair = new ConversionTypePair ( fromType , toType );
ConversionData data = null ;
lock ( converterCache )
{
if (! converterCache . TryGetValue ( pair , out data ))
{
data = new ConversionData < T >( converter , rank );
converterCache . Add ( pair , data );
}
else
{
Dbg . Assert ((( Delegate )( data . Converter )). GetMethodInfo (). Equals ( converter . GetMethodInfo ()),
"Existing conversion isn't the same as new conversion" );
}
}
return data ;
}
private static ConversionData GetConversionData ( Type fromType , Type toType )
{
lock ( converterCache )
{
ConversionData result = null ;
converterCache . TryGetValue ( new ConversionTypePair ( fromType , toType ), out result );
return result ;
}
}
internal static ConversionRank GetConversionRank ( Type fromType , Type toType )
{
return FigureConversion ( fromType , toType ). Rank ;
}
static Type [] NumericTypes = new Type [] {
typeof ( Int16 ), typeof ( Int32 ), typeof ( Int64 ),
typeof ( UInt16 ), typeof ( UInt32 ), typeof ( UInt64 ),
typeof ( SByte ), typeof ( Byte ),
typeof ( Single ), typeof ( Double ), typeof ( Decimal )
};
static Type [] IntegerTypes = new Type [] {
typeof ( Int16 ), typeof ( Int32 ), typeof ( Int64 ),
typeof ( UInt16 ), typeof ( UInt32 ), typeof ( UInt64 ),
typeof ( SByte ), typeof ( Byte )
};
// Do not reorder the elements of these arrays, we depend on them being ordered by increasing size.
static Type [] SignedIntegerTypes = new Type [] { typeof ( SByte ), typeof ( Int16 ), typeof ( Int32 ), typeof ( Int64 ) };
static Type [] UnsignedIntegerTypes = new Type [] { typeof ( Byte ), typeof ( UInt16 ), typeof ( UInt32 ), typeof ( UInt64 ) };
static Type [] RealTypes = new Type [] { typeof ( Single ), typeof ( Double ), typeof ( Decimal ) };
static internal void RebuildConversionCache ()
{
lock ( converterCache )
{
converterCache . Clear ();
Type typeofString = typeof ( string );
Type typeofNull = typeof ( Null );
Type typeofFloat = typeof ( float );
Type typeofDouble = typeof ( double );
Type typeofDecimal = typeof ( Decimal );
Type typeofBool = typeof ( bool );
Type typeofChar = typeof ( char );
foreach ( Type type in LanguagePrimitives . NumericTypes )
{
CacheConversion < string >( type , typeofString , LanguagePrimitives . ConvertNumericToString , ConversionRank . NumericString );
CacheConversion < object >( type , typeofChar , LanguagePrimitives . ConvertIConvertible , ConversionRank . NumericString );
CacheConversion < object >( typeofNull , type , LanguagePrimitives . ConvertNullToNumeric , ConversionRank . NullToValue );
}
CacheConversion < bool >( typeof ( Int16 ), typeofBool , ConvertInt16ToBool , ConversionRank . Language );
CacheConversion < bool >( typeof ( Int32 ), typeofBool , ConvertInt32ToBool , ConversionRank . Language );
CacheConversion < bool >( typeof ( Int64 ), typeofBool , ConvertInt64ToBool , ConversionRank . Language );
CacheConversion < bool >( typeof ( UInt16 ), typeofBool , ConvertUInt16ToBool , ConversionRank . Language );
CacheConversion < bool >( typeof ( UInt32 ), typeofBool , ConvertUInt32ToBool , ConversionRank . Language );
CacheConversion < bool >( typeof ( UInt64 ), typeofBool , ConvertUInt64ToBool , ConversionRank . Language );
CacheConversion < bool >( typeof ( SByte ), typeofBool , ConvertSByteToBool , ConversionRank . Language );
CacheConversion < bool >( typeof ( Byte ), typeofBool , ConvertByteToBool , ConversionRank . Language );
CacheConversion < bool >( typeof ( Single ), typeofBool , ConvertSingleToBool , ConversionRank . Language );
CacheConversion < bool >( typeof ( Double ), typeofBool , ConvertDoubleToBool , ConversionRank . Language );
CacheConversion < bool >( typeof ( Decimal ), typeofBool , ConvertDecimalToBool , ConversionRank . Language );
for ( int i = 0 ; i < LanguagePrimitives . UnsignedIntegerTypes . Length ; i ++)
{
// Identical types are an identity conversion.
CacheConversion < object >( UnsignedIntegerTypes [ i ], UnsignedIntegerTypes [ i ],
LanguagePrimitives . ConvertAssignableFrom , ConversionRank . Identity );
CacheConversion < object >( SignedIntegerTypes [ i ], SignedIntegerTypes [ i ],
LanguagePrimitives . ConvertAssignableFrom , ConversionRank . Identity );
// Unsigned to signed same size is explicit
CacheConversion < object >( UnsignedIntegerTypes [ i ], SignedIntegerTypes [ i ],
LanguagePrimitives . ConvertNumeric , ConversionRank . NumericExplicit );
// Signed to unsigned same size is explicit, but better than the reverse (because it is "more specific")
CacheConversion < object >( SignedIntegerTypes [ i ], UnsignedIntegerTypes [ i ],
LanguagePrimitives . ConvertNumeric , ConversionRank . NumericExplicit1 );
for ( int j = i + 1 ; j < LanguagePrimitives . UnsignedIntegerTypes . Length ; j ++)
{
// Conversions where the sign doesn't change, but the size is bigger, is implicit
CacheConversion < object >( UnsignedIntegerTypes [ i ], UnsignedIntegerTypes [ j ],
LanguagePrimitives . ConvertNumeric , ConversionRank . NumericImplicit );
CacheConversion < object >( SignedIntegerTypes [ i ], SignedIntegerTypes [ j ],
LanguagePrimitives . ConvertNumeric , ConversionRank . NumericImplicit );
// Conversion from smaller unsigned to bigger signed is implicit
CacheConversion < object >( UnsignedIntegerTypes [ i ], SignedIntegerTypes [ j ],
LanguagePrimitives . ConvertNumeric , ConversionRank . NumericImplicit );
// Conversion from smaller signed to bigger unsigned is the "better" explicit conversion
CacheConversion < object >( SignedIntegerTypes [ i ], UnsignedIntegerTypes [ j ],
LanguagePrimitives . ConvertNumeric , ConversionRank . NumericExplicit1 );
// Conversion to a smaller type is explicit
CacheConversion < object >( UnsignedIntegerTypes [ j ], UnsignedIntegerTypes [ i ],
LanguagePrimitives . ConvertNumeric , ConversionRank . NumericExplicit );
CacheConversion < object >( SignedIntegerTypes [ j ], SignedIntegerTypes [ i ],
LanguagePrimitives . ConvertNumeric , ConversionRank . NumericExplicit );
CacheConversion < object >( UnsignedIntegerTypes [ j ], SignedIntegerTypes [ i ],
LanguagePrimitives . ConvertNumeric , ConversionRank . NumericExplicit );
CacheConversion < object >( SignedIntegerTypes [ j ], UnsignedIntegerTypes [ i ],
LanguagePrimitives . ConvertNumeric , ConversionRank . NumericExplicit );
}
}
foreach ( Type integerType in IntegerTypes )
{
CacheConversion < object >( typeofString , integerType , LanguagePrimitives . ConvertStringToInteger , ConversionRank . NumericString );
foreach ( Type realType in RealTypes )
{
CacheConversion < object >( integerType , realType , LanguagePrimitives . ConvertNumeric , ConversionRank . NumericImplicit );
CacheConversion < object >( realType , integerType , LanguagePrimitives . ConvertNumeric , ConversionRank . NumericExplicit );
}
}
CacheConversion < object >( typeofFloat , typeofDouble , LanguagePrimitives . ConvertNumeric , ConversionRank . NumericImplicit );
CacheConversion < object >( typeofDouble , typeofFloat , LanguagePrimitives . ConvertNumeric , ConversionRank . NumericExplicit );
CacheConversion < object >( typeofFloat , typeofDecimal , LanguagePrimitives . ConvertNumeric , ConversionRank . NumericExplicit );
CacheConversion < object >( typeofDouble , typeofDecimal , LanguagePrimitives . ConvertNumeric , ConversionRank . NumericExplicit );
CacheConversion < object >( typeofDecimal , typeofFloat , LanguagePrimitives . ConvertNumeric , ConversionRank . NumericExplicit1 );
CacheConversion < object >( typeofDecimal , typeofDouble , LanguagePrimitives . ConvertNumeric , ConversionRank . NumericExplicit1 );
CacheConversion < Regex >( typeofString , typeof ( Regex ), LanguagePrimitives . ConvertStringToRegex , ConversionRank . Language );
CacheConversion < char []>( typeofString , typeof ( char []), LanguagePrimitives . ConvertStringToCharArray , ConversionRank . StringToCharArray );
CacheConversion < Type >( typeofString , typeof ( Type ), LanguagePrimitives . ConvertStringToType , ConversionRank . Language );
CacheConversion < Uri >( typeofString , typeof ( Uri ), LanguagePrimitives . ConvertStringToUri , ConversionRank . Language );
CacheConversion < object >( typeofString , typeofDecimal , LanguagePrimitives . ConvertStringToDecimal , ConversionRank . NumericString );
CacheConversion < object >( typeofString , typeofFloat , LanguagePrimitives . ConvertStringToReal , ConversionRank . NumericString );
CacheConversion < object >( typeofString , typeofDouble , LanguagePrimitives . ConvertStringToReal , ConversionRank . NumericString );
CacheConversion < object >( typeofChar , typeofFloat , LanguagePrimitives . ConvertNumericChar , ConversionRank . Language );
CacheConversion < object >( typeofChar , typeofDouble , LanguagePrimitives . ConvertNumericChar , ConversionRank . Language );
CacheConversion < bool >( typeofChar , typeofBool , LanguagePrimitives . ConvertCharToBool , ConversionRank . Language );
// Conversions from null
CacheConversion < char >( typeofNull , typeofChar , LanguagePrimitives . ConvertNullToChar , ConversionRank . NullToValue );
CacheConversion < string >( typeofNull , typeofString , LanguagePrimitives . ConvertNullToString , ConversionRank . ToString );
CacheConversion < bool >( typeofNull , typeofBool , LanguagePrimitives . ConvertNullToBool , ConversionRank . NullToValue );
CacheConversion < PSReference >( typeofNull , typeof ( PSReference ), LanguagePrimitives . ConvertNullToPSReference , ConversionRank . NullToRef );
CacheConversion < SwitchParameter >( typeofNull , typeof ( SwitchParameter ), LanguagePrimitives . ConvertNullToSwitch , ConversionRank . NullToValue );
CacheConversion < object >( typeofNull , typeof ( void ), LanguagePrimitives . ConvertNullToVoid , ConversionRank . NullToValue );
// Conversions to bool
CacheConversion < object >( typeofBool , typeofBool , LanguagePrimitives . ConvertAssignableFrom , ConversionRank . Identity );
CacheConversion < bool >( typeofString , typeofBool , LanguagePrimitives . ConvertStringToBool , ConversionRank . Language );
CacheConversion < bool >( typeof ( SwitchParameter ), typeofBool , LanguagePrimitives . ConvertSwitchParameterToBool , ConversionRank . Language );
#if ! CORECLR // No DirectoryService && WMIv1 In CoreCLR
CacheConversion < ManagementObjectSearcher >( typeofString , typeof ( ManagementObjectSearcher ), LanguagePrimitives . ConvertToWMISearcher , ConversionRank . Language );
CacheConversion < ManagementClass >( typeofString , typeof ( ManagementClass ), LanguagePrimitives . ConvertToWMIClass , ConversionRank . Language );
CacheConversion < ManagementObject >( typeofString , typeof ( ManagementObject ), LanguagePrimitives . ConvertToWMI , ConversionRank . Language );
CacheConversion < DirectoryEntry >( typeofString , typeof ( DirectoryEntry ), LanguagePrimitives . ConvertToADSI , ConversionRank . Language );
CacheConversion < DirectorySearcher >( typeofString , typeof ( DirectorySearcher ), LanguagePrimitives . ConvertToADSISearcher , ConversionRank . Language );
#endif
}
}
internal static PSObject SetObjectProperties ( object o , PSObject psObject , Type resultType , MemberNotFoundError memberNotFoundErrorAction , MemberSetValueError memberSetValueErrorAction , IFormatProvider formatProvider , bool recursion = false , bool ignoreUnknownMembers = false )
{
// Type conversion from object properties only supported for deserialized types.
if ( Deserializer . IsDeserializedInstanceOfType ( psObject , resultType ))
{
try
{
Dictionary < string , object > properties = new Dictionary < string , object >();
foreach ( var item in psObject . Properties )
{
if ( item is PSProperty )
{
properties . Add ( item . Name , item . Value );
}
}
// Win8:649519
return SetObjectProperties ( o , properties , resultType , memberNotFoundErrorAction , memberSetValueErrorAction , enableMethodCall : false );
}
catch ( SetValueException )
{ }
catch ( InvalidOperationException )
{ }
}
else
{
object baseObj = PSObject . Base ( psObject );
var dictionary = baseObj as IDictionary ;
if ( dictionary != null )
{
// Win8:649519
return SetObjectProperties ( o , dictionary , resultType , memberNotFoundErrorAction , memberSetValueErrorAction , enableMethodCall : false );
}
else
{
// Support PSObject to Strong type conversion.
PSObject psBaseObject = baseObj as PSObject ;
if ( psBaseObject != null )
{
Dictionary < string , object > properties = new Dictionary < string , object >();
foreach ( var item in psBaseObject . Properties )
{
properties . Add ( item . Name , item . Value );
}
try
{
return SetObjectProperties ( o , properties , resultType , memberNotFoundErrorAction , memberSetValueErrorAction , false , formatProvider , recursion , ignoreUnknownMembers );
}
catch ( InvalidOperationException exception )
{
throw new PSInvalidCastException ( "ConvertToFinalInvalidCastException" , exception ,
ExtendedTypeSystem . InvalidCastException ,
psObject . ToString (), ObjectToTypeNameString ( psObject ),
resultType . ToString ());
}
}
}
}
ThrowInvalidCastException ( psObject , resultType );
return null ;
}
internal static PSObject SetObjectProperties ( object o , IDictionary properties , Type resultType , MemberNotFoundError memberNotFoundErrorAction , MemberSetValueError memberSetValueErrorAction , bool enableMethodCall )
{
return SetObjectProperties ( o , properties , resultType , memberNotFoundErrorAction , memberSetValueErrorAction , enableMethodCall , CultureInfo . InvariantCulture , false , false );
}
internal static PSObject SetObjectProperties ( object o , IDictionary properties , Type resultType , MemberNotFoundError memberNotFoundErrorAction , MemberSetValueError memberSetValueErrorAction , bool enableMethodCall , IFormatProvider formatProvider , bool recursion = false , bool ignoreUnknownMembers = false )
{
PSObject pso = PSObject . AsPSObject ( o );
if ( properties != null )
{
foreach ( DictionaryEntry prop in properties )
{
PSMethodInfo method = enableMethodCall ? pso . Methods [ prop . Key . ToString ()] : null ;
try
{
if ( method != null )
{
method . Invoke ( new object [] { prop . Value });
}
else
{
PSPropertyInfo property = pso . Properties [ prop . Key . ToString ()];
if ( property != null )
{
object propValue = prop . Value ;
if ( recursion && prop . Value != null )
{
Type propType ;
if ( TypeResolver . TryResolveType ( property . TypeNameOfValue , out propType ))
{
if ( formatProvider == null ) { formatProvider = CultureInfo . InvariantCulture ; }
try
{
PSObject propertyValue = prop . Value as PSObject ;
if ( propertyValue != null )
{
propValue = LanguagePrimitives . ConvertPSObjectToType ( propertyValue , propType , recursion , formatProvider , ignoreUnknownMembers );
}
else if ( prop . Value is PSCustomObject )
{
propValue = LanguagePrimitives . ConvertPSObjectToType ( new PSObject ( prop . Value ), propType , recursion , formatProvider , ignoreUnknownMembers );
}
else
{
propValue = LanguagePrimitives . ConvertTo ( prop . Value , propType , recursion , formatProvider , null );
}
}
catch ( SetValueException )
{
// We don't care. We will assign the value as is.
}
}
}
property . Value = propValue ;
}
else
{
if ( pso . BaseObject is PSCustomObject )
{
var key = prop . Key as string ;
var value = prop . Value as string ;
if ( key != null && value != null && key . Equals ( "PSTypeName" , StringComparison . OrdinalIgnoreCase ))
{
pso . TypeNames . Insert ( 0 , value );
}
else
{
pso . Properties . Add ( new PSNoteProperty ( prop . Key . ToString (), prop . Value ));
}
}
else
{
if (! ignoreUnknownMembers )
{
memberNotFoundErrorAction ( pso , prop , resultType );
}
}
}
}
}
catch ( SetValueException e )
{
memberSetValueErrorAction ( e );
}
}
}
return pso ;
}
private static String GetAvailableProperties ( PSObject pso )
{
StringBuilder availableProperties = new StringBuilder ();
bool first = true ;
if ( pso != null && pso . Properties != null )
{
foreach ( PSPropertyInfo p in pso . Properties )
{
if ( first == false )
{
availableProperties . Append ( " , " );
}
availableProperties . Append ( "[" + p . Name + " <" + p . TypeNameOfValue + ">]" );
if ( first == true )
{
first = false ;
}
}
}
return availableProperties . ToString ();
}
internal static ConversionData FigureConversion ( object valueToConvert , Type resultType , out bool debase )
{
PSObject valueAsPsObj ;
Type originalType ;
if ( valueToConvert == null || valueToConvert == AutomationNull . Value )
{
valueAsPsObj = null ;
originalType = typeof ( Null );
}
else
{
valueAsPsObj = valueToConvert as PSObject ;
originalType = valueToConvert . GetType ();
}
debase = false ;
ConversionData data = FigureConversion ( originalType , resultType );
if ( data . Rank != ConversionRank . None )
{
return data ;
}
if ( valueAsPsObj != null )
{
debase = true ;
// Now try converting PSObject.Base instead.
valueToConvert = PSObject . Base ( valueToConvert );
Dbg . Assert ( valueToConvert != AutomationNull . Value , "PSObject.Base converts AutomationNull.Value to null" );
if ( valueToConvert == null )
{
originalType = typeof ( Null );
}
else
{
// If the original value was a property bag (empty PSObject), we won't find a conversion because
// all PSObject conversions have already been checked.
//
// Still, there are many valid conversions to allow, such as PSObject to bool, void, or
// a custom type converter. To find those, we consider InternalPSObject=>resultType instead.
//
// We use a different type because we can't keep PSObject as the from type in the cache.
originalType = ( valueToConvert is PSObject ) ? typeof ( InternalPSObject ) : valueToConvert . GetType ();
}
data = FigureConversion ( originalType , resultType );
}
return data ;
}
/// <summary>
///
/// </summary>
/// <param name="valueToConvert">the same as in the public version</param>
/// <param name="resultType">the same as in the public version</param>
/// <param name="recursion">true if we should perform any recursive calls to ConvertTo</param>
/// <param name="formatProvider">governing conversion of types</param>
/// <param name="backupTypeTable">
/// Used by Remoting Rehydration Logic. While Deserializing a remote object,
/// LocalPipeline.ExecutionCotextFromTLS() might return null..In which case this
/// TypeTable will be used to do the conversion.
/// </param>
/// <returns>the value converted</returns>
/// <exception cref="ArgumentNullException">if resultType is null</exception>
/// <exception cref="PSInvalidCastException">if the conversion failed</exception>
internal static object ConvertTo ( object valueToConvert ,
Type resultType ,
bool recursion ,
IFormatProvider formatProvider ,
TypeTable backupTypeTable )
{
using ( typeConversion . TraceScope ( "Converting \"{0}\" to \"{1}\"." , valueToConvert , resultType ))
{
if ( resultType == null )
{
throw PSTraceSource . NewArgumentNullException ( "resultType" );
}
bool debase ;
var conversion = FigureConversion ( valueToConvert , resultType , out debase );
return conversion . Invoke ( debase ? PSObject . Base ( valueToConvert ) : valueToConvert ,
resultType , recursion , debase ? ( PSObject ) valueToConvert : null ,
formatProvider , backupTypeTable );
}
}
/// <summary>
/// Get the errorId and errorMessage for an InvalidCastException
/// </summary>
/// <param name="valueToConvert"></param>
/// <param name="resultType"></param>
/// <returns>
/// A two-element tuple indicating [errorId, errorMsg]
/// </returns>
internal static Tuple < string , string > GetInvalidCastMessages ( object valueToConvert , Type resultType )
{
string errorId , errorMsg ;
if ( PSObject . Base ( valueToConvert ) == null )
{
if ( resultType . GetTypeInfo (). IsEnum )
{
typeConversion . WriteLine ( "Issuing an error message about not being able to convert null to an Enum type." );
// a nice error message specifically for null being converted to enum
errorId = "nullToEnumInvalidCast" ;
errorMsg = StringUtil . Format ( ExtendedTypeSystem . InvalidCastExceptionEnumerationNull , resultType ,
EnumSingleTypeConverter . EnumValues ( resultType ));
return Tuple . Create ( errorId , errorMsg );
}
typeConversion . WriteLine ( "Cannot convert null." );
// finally throw of all other value types...
errorId = "nullToObjectInvalidCast" ;
errorMsg = StringUtil . Format ( ExtendedTypeSystem . InvalidCastFromNull , resultType . ToString ());
return Tuple . Create ( errorId , errorMsg );
}
typeConversion . WriteLine ( "Type Conversion failed." );
errorId = "ConvertToFinalInvalidCastException" ;
errorMsg = StringUtil . Format ( ExtendedTypeSystem . InvalidCastException , valueToConvert . ToString (),
ObjectToTypeNameString ( valueToConvert ), resultType . ToString ());
return Tuple . Create ( errorId , errorMsg );
}
// Even though this never returns, expression trees expect non-void values in places, and so it's easier
// to claim it returns object than to add extra expressions to keep the trees type safe.
internal static object ThrowInvalidCastException ( object valueToConvert , Type resultType )
{
// Get exception messages (in order): errorId, errorMsg
var errorMsgTuple = GetInvalidCastMessages ( valueToConvert , resultType );
throw new PSInvalidCastException ( errorMsgTuple . Item1 , errorMsgTuple . Item2 , innerException : null );
}
// Even though this never returns, expression trees expect non-void values in places, and so it's easier
// to claim it returns object than to add extra expressions to keep the trees type safe.
internal static object ThrowInvalidConversionException ( object valueToConvert , Type resultType )
{
typeConversion . WriteLine ( "Issuing an error message about not being able to convert to non-core type." );
throw new PSInvalidCastException ( "ConversionSupportedOnlyToCoreTypes" , null , ExtendedTypeSystem . InvalidCastExceptionNonCoreType , resultType . ToString ());
}
private static ConversionData FigureLanguageConversion ( Type fromType , Type toType ,
out PSConverter < object > valueDependentConversion ,
out ConversionRank valueDependentRank )
{
valueDependentConversion = null ;
valueDependentRank = ConversionRank . None ;
Type underlyingType = Nullable . GetUnderlyingType ( toType );
if ( underlyingType != null )
{
ConversionData nullableConversion = FigureConversion ( fromType , underlyingType );
if ( nullableConversion . Rank != ConversionRank . None )
{
return CacheConversion < object >( fromType , toType , LanguagePrimitives . ConvertToNullable , nullableConversion . Rank );
}
}
if ( toType == typeof ( void ))
{
return CacheConversion < object >( fromType , toType , LanguagePrimitives . ConvertToVoid , ConversionRank . Language );
}
if ( toType == typeof ( bool ))
{
PSConverter < bool > converter ;
if ( typeof ( IList ). IsAssignableFrom ( fromType ))
{
converter = LanguagePrimitives . ConvertIListToBool ;
}
else if ( fromType . GetTypeInfo (). IsEnum )
{
converter = LanguagePrimitives . CreateNumericToBoolConverter ( fromType );
}
else if ( fromType . GetTypeInfo (). IsValueType )
{
converter = LanguagePrimitives . ConvertValueToBool ;
}
else
{
converter = LanguagePrimitives . ConvertClassToBool ;
}
return CacheConversion < bool >( fromType , toType , converter , ConversionRank . Language );
}
if ( toType == typeof ( string ))
{
Dbg . Assert (! LanguagePrimitives . IsNumeric ( LanguagePrimitives . GetTypeCode ( fromType )) || fromType . GetTypeInfo (). IsEnum ,
"Number to string should be cached on initialization of cache table" );
return CacheConversion < string >( fromType , toType , LanguagePrimitives . ConvertNonNumericToString , ConversionRank . ToString );
}
if ( toType . IsArray )
{
Type toElementType = toType . GetElementType ();
if ( fromType . IsArray )
{
if ( toElementType . IsAssignableFrom ( fromType . GetElementType ()))
{
return CacheConversion < object >( fromType , toType , LanguagePrimitives . ConvertRelatedArrays , ConversionRank . Language );
}
return CacheConversion < object >( fromType , toType , LanguagePrimitives . ConvertUnrelatedArrays , ConversionRank . UnrelatedArrays );
}
if ( LanguagePrimitives . IsTypeEnumerable ( fromType ))
{
return CacheConversion < object >( fromType , toType , LanguagePrimitives . ConvertEnumerableToArray , ConversionRank . Language );
}
ConversionData data = FigureConversion ( fromType , toElementType );
if ( data . Rank != ConversionRank . None )
{
valueDependentRank = data . Rank & ConversionRank . ValueDependent ;
valueDependentConversion = LanguagePrimitives . ConvertScalarToArray ;
return null ;
}
}
if ( toType == typeof ( Array ))
{
if ( fromType . IsArray || fromType == typeof ( Array ))
{
return CacheConversion < object >( fromType , toType , LanguagePrimitives . ConvertAssignableFrom , ConversionRank . Assignable );
}
if ( LanguagePrimitives . IsTypeEnumerable ( fromType ))
{
return CacheConversion < object >( fromType , toType , LanguagePrimitives . ConvertEnumerableToArray , ConversionRank . Language );
}
valueDependentRank = ConversionRank . Assignable & ConversionRank . ValueDependent ;
valueDependentConversion = LanguagePrimitives . ConvertScalarToArray ;
return null ;
}
if ( toType == typeof ( Hashtable ))
{
if ( typeof ( IDictionary ). IsAssignableFrom ( fromType ))
{
return CacheConversion < Hashtable >( fromType , toType , LanguagePrimitives . ConvertIDictionaryToHashtable , ConversionRank . Language );
}
else
{
return null ;
}
}
if ( toType == typeof ( PSReference ))
{
return CacheConversion < PSReference >( fromType , toType , LanguagePrimitives . ConvertToPSReference , ConversionRank . Language );
}
if ( toType == typeof ( XmlDocument ))
{
return CacheConversion < XmlDocument >( fromType , toType , LanguagePrimitives . ConvertToXml , ConversionRank . Language );
}
if ( toType == typeof ( StringCollection ))
{
ConversionRank rank = ( fromType . IsArray || IsTypeEnumerable ( fromType )) ? ConversionRank . Language : ConversionRank . LanguageS2A ;
return CacheConversion < StringCollection >( fromType , toType , LanguagePrimitives . ConvertToStringCollection , rank );
}
#if ! CORECLR // No CommaDelimitedStringCollection In CoreCLR
if ( toType == typeof ( System . Configuration . CommaDelimitedStringCollection ))
{
ConversionRank rank = ( fromType . IsArray || IsTypeEnumerable ( fromType )) ? ConversionRank . Language : ConversionRank . LanguageS2A ;
return CacheConversion < System . Configuration . CommaDelimitedStringCollection >( fromType , toType , LanguagePrimitives . ConvertToCommaDelimitedStringCollection , rank );
}
#endif
if ( toType . IsSubclassOf ( typeof ( System . Delegate ))
&& ( fromType == typeof ( ScriptBlock ) || fromType . IsSubclassOf ( typeof ( ScriptBlock ))))
{
return CacheConversion < Delegate >( fromType , toType , LanguagePrimitives . ConvertScriptBlockToDelegate , ConversionRank . Language );
}
if ( toType == typeof ( InternalPSCustomObject ))
{
Type actualResultType = typeof ( PSObject );
ConstructorInfo resultConstructor = actualResultType . GetConstructor ( PSTypeExtensions . EmptyTypes );
var converterObj = new ConvertViaNoArgumentConstructor ( resultConstructor , actualResultType );
return CacheConversion ( fromType , toType , converterObj . Convert , ConversionRank . Language );
}
TypeCode fromTypeCode = LanguagePrimitives . GetTypeCode ( fromType );
if ( LanguagePrimitives . IsInteger ( fromTypeCode ) && toType . GetTypeInfo (). IsEnum )
{
return CacheConversion < object >( fromType , toType , LanguagePrimitives . ConvertIntegerToEnum , ConversionRank . Language );
}
return null ;
}
private static PSConverter < object > FigureStaticCreateMethodConversion ( Type fromType , Type toType )
{
// after discussing this with Jason, we decided that for now we only want to support string->CimSession conversion
// and we don't want to add a Parse-like conversion based on a static Create method
if ( fromType == typeof ( string ) && toType == typeof ( Microsoft . Management . Infrastructure . CimSession ))
{
return LanguagePrimitives . ConvertStringToCimSession ;
}
return null ;
}
private static PSConverter < object > FigureParseConversion ( Type fromType , Type toType )
{
if ( toType . GetTypeInfo (). IsEnum )
{
if ( fromType == typeof ( string ))
{
return LanguagePrimitives . ConvertStringToEnum ;
}
if ( LanguagePrimitives . IsTypeEnumerable ( fromType ))
{
return LanguagePrimitives . ConvertEnumerableToEnum ;
}
}
else if ( fromType == typeof ( string ))
{
const BindingFlags parseFlags = BindingFlags . FlattenHierarchy | BindingFlags . Public | BindingFlags . Static ;
// GetMethod could throw for more than one match, for instance
MethodInfo parse = null ;
try
{
parse = toType . GetMethod ( "Parse" , parseFlags , null , new Type [ 2 ] { typeof ( string ), typeof ( IFormatProvider ) }, null );
}
catch ( AmbiguousMatchException e )
{
typeConversion . WriteLine ( "Exception finding Parse method with CultureInfo: \"{0}\"." , e . Message );
}
catch ( ArgumentException e )
{
typeConversion . WriteLine ( "Exception finding Parse method with CultureInfo: \"{0}\"." , e . Message );
}
if ( parse != null )
{
ConvertViaParseMethod converter = new ConvertViaParseMethod ();
converter . parse = parse ;
return converter . ConvertWithCulture ;
}
try
{
parse = toType . GetMethod ( "Parse" , parseFlags , null , new Type [ 1 ] { typeof ( string ) }, null );
}
catch ( AmbiguousMatchException e )
{
typeConversion . WriteLine ( "Exception finding Parse method: \"{0}\"." , e . Message );
}
catch ( ArgumentException e )
{
typeConversion . WriteLine ( "Exception finding Parse method: \"{0}\"." , e . Message );
}
if ( parse != null )
{
ConvertViaParseMethod converter = new ConvertViaParseMethod ();
converter . parse = parse ;
return converter . ConvertWithoutCulture ;
}
}
return null ;
}
/// <summary>
/// Figure conversion when following conditions are satisfied:
/// 1. toType is a closed generic type and it has a constructor that takes IEnumerable[T], ICollection[T] or IList[T]
/// 2. fromType is System.Array, System.Object[] or it's the same as the element type of toType
/// </summary>
/// <param name="fromType"></param>
/// <param name="toType"></param>
/// <returns></returns>
internal static Tuple < PSConverter < object >, ConversionRank > FigureIEnumerableConstructorConversion ( Type fromType , Type toType )
{
// Win8: 653180. If toType is an Abstract type then we cannot construct it anyway. So, bailing out fast.
TypeInfo toTypeInfo = toType . GetTypeInfo ();
if ( toTypeInfo . IsAbstract == true )
{
return null ;
}
try
{
bool result = false ;
bool isScalar = false ;
Type elementType = null ;
ConstructorInfo resultConstructor = null ;
if ( toTypeInfo . IsGenericType && ! toTypeInfo . ContainsGenericParameters &&
( typeof ( IList ). IsAssignableFrom ( toType ) ||
typeof ( ICollection ). IsAssignableFrom ( toType ) ||
typeof ( IEnumerable ). IsAssignableFrom ( toType )))
{
Type [] argTypes = toType . GetGenericArguments ();
if ( argTypes . Length != 1 )
{
typeConversion
. WriteLine (
"toType has more than one generic arguments. Here we only care about the toType which contains only one generic argument and whose constructor takes IEnumerable<T>, ICollection<T> or IList<T>." );
return null ;
}
elementType = argTypes [ 0 ];
if ( typeof ( Array ) == fromType || typeof ( object []) == fromType ||
elementType . IsAssignableFrom ( fromType ) ||
// WinBlue: 423899 : To support scenario like [list[int]]"4"
( FigureConversion ( fromType , elementType ) != null ))
{
isScalar = elementType . IsAssignableFrom ( fromType );
ConstructorInfo [] ctors = toType . GetConstructors ();
Type iEnumerableClosedType = typeof ( IEnumerable <>). MakeGenericType ( elementType );
Type iCollectionClosedType = typeof ( ICollection <>). MakeGenericType ( elementType );
Type iListClosedType = typeof ( IList <>). MakeGenericType ( elementType );
foreach ( var ctor in ctors )
{
ParameterInfo [] param = ctor . GetParameters ();
if ( param . Length != 1 )
continue ;
Type paramType = param [ 0 ]. ParameterType ;
if ( iEnumerableClosedType == paramType ||
iCollectionClosedType == paramType ||
iListClosedType == paramType )
{
resultConstructor = ctor ;
result = true ;
break ;
}
}
}
}
if ( result )
{
var converter = new ConvertViaIEnumerableConstructor ();
try
{
Type listClosedType = typeof ( List <>). MakeGenericType ( elementType );
ConstructorInfo listCtor = listClosedType . GetConstructor ( new Type [] { typeof ( int )});
converter . ListCtorLambda = CreateCtorLambdaClosure < int , IList >( listCtor , typeof ( int ), false );
ParameterInfo [] targetParams = resultConstructor . GetParameters ();
Type targetParamType = targetParams [ 0 ]. ParameterType ;
converter . TargetCtorLambda = CreateCtorLambdaClosure < IList , object >( resultConstructor ,
targetParamType , false );
converter . ElementType = elementType ;
converter . IsScalar = isScalar ;
}
catch ( Exception e )
{
CommandProcessorBase . CheckForSevereException ( e );
typeConversion . WriteLine ( "Exception building constructor lambda: \"{0}\"" , e . Message );
return null ;
}
ConversionRank rank = isScalar ? ConversionRank . ConstructorS2A : ConversionRank . Constructor ;
typeConversion . WriteLine ( "Conversion is figured out. Conversion rank: \"{0}\"" , rank );
return new Tuple < PSConverter < object >, ConversionRank >( converter . Convert , rank );
}
else
{
typeConversion . WriteLine ( "Fail to figure out the conversion from \"{0}\" to \"{1}\"" ,
fromType . FullName , toType . FullName );
return null ;
}
}
catch ( ArgumentException ae )
{
typeConversion . WriteLine ( "Exception finding IEnumerable conversion: \"{0}\"." , ae . Message );
}
catch ( InvalidOperationException ie )
{
typeConversion . WriteLine ( "Exception finding IEnumerable conversion: \"{0}\"." , ie . Message );
}
catch ( NotSupportedException ne )
{
typeConversion . WriteLine ( "Exception finding IEnumerable conversion: \"{0}\"." , ne . Message );
}
return null ;
}
private static Func < T1 , T2 > CreateCtorLambdaClosure < T1 , T2 >( ConstructorInfo ctor , Type realParamType , bool useExplicitConversion )
{
ParameterExpression paramExpr = Expression . Parameter ( typeof ( T1 ), "args" );
Expression castParamExpr = useExplicitConversion
? ( Expression ) Expression . Call ( CachedReflectionInfo . Convert_ChangeType , paramExpr , Expression . Constant ( realParamType , typeof ( Type )))
: Expression . Convert ( paramExpr , realParamType );
NewExpression ctorExpr = Expression . New ( ctor , castParamExpr . Cast ( realParamType ));
return Expression . Lambda < Func < T1 , T2 >>( ctorExpr . Cast ( typeof ( T2 )), paramExpr ). Compile ();
}
internal static PSConverter < object > FigureConstructorConversion ( Type fromType , Type toType )
{
if ( IsIntegralType ( fromType ) &&
( typeof ( IList ). IsAssignableFrom ( toType ) || typeof ( ICollection ). IsAssignableFrom ( toType )))
{
typeConversion . WriteLine ( "Ignoring the collection constructor that takes an integer, since this is not semantically a conversion." );
return null ;
}
ConstructorInfo resultConstructor = null ;
try
{
resultConstructor = toType . GetConstructor ( new Type [] { fromType });
}
catch ( AmbiguousMatchException e )
{
typeConversion . WriteLine ( "Exception finding Constructor: \"{0}\"." , e . Message );
}
catch ( ArgumentException e )
{
typeConversion . WriteLine ( "Exception finding Constructor: \"{0}\"." , e . Message );
}
if ( resultConstructor == null )
{
return null ;
}
typeConversion . WriteLine ( "Found Constructor." );
var converter = new ConvertViaConstructor ();
try
{
ParameterInfo [] targetParams = resultConstructor . GetParameters ();
Type targetParamType = targetParams [ 0 ]. ParameterType ;
bool useExplicitConversion = targetParamType . GetTypeInfo (). IsValueType && fromType != targetParamType && Nullable . GetUnderlyingType ( targetParamType ) == null ;
converter . TargetCtorLambda = CreateCtorLambdaClosure < object , object >( resultConstructor , targetParamType , useExplicitConversion );
}
catch ( Exception e )
{
CommandProcessorBase . CheckForSevereException ( e );
typeConversion . WriteLine ( "Exception building constructor lambda: \"{0}\"" , e . Message );
return null ;
}
typeConversion . WriteLine ( "Conversion is figured out." );
return converter . Convert ;
}
private static bool IsIntegralType ( Type type )
{
return
type == typeof ( sbyte ) ||
type == typeof ( byte ) ||
type == typeof ( short ) ||
type == typeof ( ushort ) ||
type == typeof ( int ) ||
type == typeof ( uint ) ||
type == typeof ( long ) ||
type == typeof ( ulong );
}
internal static PSConverter < object > FigurePropertyConversion ( Type fromType , Type toType , ref ConversionRank rank )
{
TypeInfo toTypeInfo = toType . GetTypeInfo ();
if ((! typeof ( PSObject ). IsAssignableFrom ( fromType )) || ( toTypeInfo . IsAbstract ))
{
return null ;
}
ConstructorInfo toConstructor = null ;
try
{
toConstructor = toType . GetConstructor ( PSTypeExtensions . EmptyTypes );
}
catch ( AmbiguousMatchException e )
{
typeConversion . WriteLine ( "Exception finding Constructor: \"{0}\"." , e . Message );
}
catch ( ArgumentException e )
{
typeConversion . WriteLine ( "Exception finding Constructor: \"{0}\"." , e . Message );
}
if ( toConstructor == null && ! toTypeInfo . IsValueType )
{
return null ;
}
if ( toType . GetProperties ( BindingFlags . Public | BindingFlags . Instance ). Length == 0 &&
toType . GetFields ( BindingFlags . Public | BindingFlags . Instance ). Length == 0 )
{
// fromType is PSObject, toType has no properties/fields to set, so conversion should fail.
return null ;
}
typeConversion . WriteLine ( "Found Constructor." );
try
{
ConvertViaNoArgumentConstructor noArgumentConstructorConverter =
new ConvertViaNoArgumentConstructor ( toConstructor , toType );
rank = ConversionRank . Constructor ;
return noArgumentConstructorConverter . Convert ;
}
catch ( ArgumentException ae )
{
typeConversion . WriteLine ( "Exception converting via no argument constructor: \"{0}\"." , ae . Message );
}
catch ( InvalidOperationException ie )
{
typeConversion . WriteLine ( "Exception converting via no argument constructor: \"{0}\"." , ie . Message );
}
rank = ConversionRank . None ;
return null ;
}
internal static PSConverter < object > FigureCastConversion ( Type fromType , Type toType , ref ConversionRank rank )
{
MethodInfo castOperator = FindCastOperator ( "op_Implicit" , toType , fromType , toType );
if ( castOperator == null )
{
castOperator = FindCastOperator ( "op_Explicit" , toType , fromType , toType );
if ( castOperator == null )
{
castOperator = FindCastOperator ( "op_Implicit" , fromType , fromType , toType );
if ( castOperator == null )
{
castOperator = FindCastOperator ( "op_Explicit" , fromType , fromType , toType );
}
}
}
if ( castOperator != null )
{
rank = castOperator . Name . Equals ( "op_Implicit" , StringComparison . OrdinalIgnoreCase )
? ConversionRank . ImplicitCast : ConversionRank . ExplicitCast ;
ConvertViaCast converter = new ConvertViaCast ();
converter . cast = castOperator ;
return converter . Convert ;
}
return null ;
}
private static bool TypeConverterPossiblyExists ( Type type )
{
lock ( possibleTypeConverter )
{
if ( possibleTypeConverter . ContainsKey ( type . FullName ))
{
return true ;
}
}
// GetCustomAttributes returns IEnumerable<Attribute> in CoreCLR
var typeConverters = type . GetTypeInfo (). GetCustomAttributes ( typeof ( TypeConverterAttribute ), false );
if ( typeConverters . Any ())
{
return true ;
}
return false ;
}
private static Dictionary < string , bool > possibleTypeConverter = new Dictionary < string , bool >( 16 );
// This is the internal dummy type used when an IDictionary is converted to a pscustomobject
// PS C:\> $ps = [pscustomobject]@{a=10;b=5}
// PS C:\> $ps = [pscustomobject][ordered]@{a=10;b=5}
// Whenever we see a conversion to PSCustomObject, we represent it as a conversion to InternalPSCustomObject
// This is introduced to avoid breaking PSObject behavior.
// (Because PSCustomObject is a typeaccelerator for PSObject, we needed a separate type to represent type conversions to PSCustomObject)
internal class InternalPSCustomObject
{
}
internal class InternalPSObject : PSObject { }
internal static ConversionData FigureConversion ( Type fromType , Type toType )
{
ConversionData data = GetConversionData ( fromType , toType );
if ( data != null )
{
return data ;
}
if ( fromType == typeof ( Null ))
{
return FigureConversionFromNull ( toType );
}
if ( toType . IsAssignableFrom ( fromType ))
{
return CacheConversion < object >( fromType , toType , LanguagePrimitives . ConvertAssignableFrom ,
toType == fromType ? ConversionRank . Identity : ConversionRank . Assignable );
}
if ( typeof ( PSObject ). IsAssignableFrom ( fromType ) && typeof ( InternalPSObject ) != fromType )
{
// We don't attempt converting PSObject (or derived) to anything else,
// instead we go straight to PSObject.Base (which is only a PSObject
// when no object is wrapped, in which case we try conversions from object)
// and convert that instead.
return CacheConversion ( fromType , toType , ConvertNoConversion , ConversionRank . None );
}
if ( toType == typeof ( PSObject ))
{
return CacheConversion < PSObject >( fromType , toType , LanguagePrimitives . ConvertToPSObject , ConversionRank . PSObject );
}
PSConverter < object > converter = null ;
ConversionRank rank = ConversionRank . None ;
// If we've ever used ConstrainedLanguage, check if the target type is allowed
if ( ExecutionContext . HasEverUsedConstrainedLanguage )
{
var context = LocalPipeline . GetExecutionContextFromTLS ();
if (( context != null ) && ( context . LanguageMode == PSLanguageMode . ConstrainedLanguage ))
{
if (( toType != typeof ( Object )) &&
( toType != typeof ( Object [])) &&
(! CoreTypes . Contains ( toType )))
{
converter = ConvertNotSupportedConversion ;
rank = ConversionRank . None ;
return CacheConversion ( fromType , toType , converter , rank );
}
}
}
#if CORECLR
// Assemblies in CoreCLR might not allow reflection execution on their internal types.
TypeInfo typeInfo = toType . GetTypeInfo ();
if (! TypeResolver . IsPublic ( typeInfo ) && DotNetAdapter . DisallowPrivateReflection ( typeInfo ))
{
// If the type is non-public and reflection execution is not allowed on it, then we return
// 'ConvertNoConversion', because we won't be able to invoke constructor, methods or set
// properties on an instance of this type through reflection.
return CacheConversion ( fromType , toType , ConvertNoConversion , ConversionRank . None );
}
#endif
PSConverter < object > valueDependentConversion = null ;
ConversionRank valueDependentRank = ConversionRank . None ;
ConversionData conversionData = FigureLanguageConversion ( fromType , toType , out valueDependentConversion , out valueDependentRank );
if ( conversionData != null )
{
return conversionData ;
}
rank = valueDependentConversion != null ? ConversionRank . Language : ConversionRank . None ;
converter = FigureParseConversion ( fromType , toType );
if ( converter == null )
{
converter = FigureStaticCreateMethodConversion ( fromType , toType );
if ( converter == null )
{
converter = FigureConstructorConversion ( fromType , toType );
rank = ConversionRank . Constructor ;
if ( converter == null )
{
converter = FigureCastConversion ( fromType , toType , ref rank );
if ( converter == null )
{
if ( typeof ( IConvertible ). IsAssignableFrom ( fromType ))
{
if ( LanguagePrimitives . IsNumeric ( GetTypeCode ( fromType )) && ! fromType . GetTypeInfo (). IsEnum )
{
if (! toType . IsArray )
{
if ( GetConversionRank ( typeof ( string ), toType ) != ConversionRank . None )
{
converter = LanguagePrimitives . ConvertNumericIConvertible ;
rank = ConversionRank . IConvertible ;
}
}
}
else if ( fromType != typeof ( string ))
{
converter = LanguagePrimitives . ConvertIConvertible ;
rank = ConversionRank . IConvertible ;
}
}
else if ( typeof ( IDictionary ). IsAssignableFrom ( fromType ))
{
// We need to call the null argument constructor only if the following 2 conditions satisfy
// 1) if the fromType is either a hashtable or OrderedDictionary
// 2) if the ToType does not already have a constructor that takes a hashtable or OrderedDictionary. (This is to avoid breaking existing apps.)
// If the ToType has a constructor that takes a hashtable or OrderedDictionary,
// then it would have been returned as the constructor during FigureConstructorConversion
// So, we need to check only for the first condition
ConstructorInfo resultConstructor = toType . GetConstructor ( PSTypeExtensions . EmptyTypes );
TypeInfo toTypeInfo = toType . GetTypeInfo ();
if ( resultConstructor != null || ( toTypeInfo . IsValueType && ! toTypeInfo . IsPrimitive ))
{
ConvertViaNoArgumentConstructor noArgumentConstructorConverter = new ConvertViaNoArgumentConstructor ( resultConstructor , toType );
converter = noArgumentConstructorConverter . Convert ;
rank = ConversionRank . Constructor ;
}
}
}
}
else
{
rank = ConversionRank . Constructor ;
}
}
else
{
rank = ConversionRank . Create ;
}
}
else
{
rank = ConversionRank . Parse ;
}
if ( converter == null )
{
var tuple = FigureIEnumerableConstructorConversion ( fromType , toType );
if ( tuple != null )
{
converter = tuple . Item1 ;
rank = tuple . Item2 ;
}
}
if ( converter == null )
{
converter = FigurePropertyConversion ( fromType , toType , ref rank );
}
if ( TypeConverterPossiblyExists ( fromType ) || TypeConverterPossiblyExists ( toType )
|| ( converter != null && valueDependentConversion != null ))
{
ConvertCheckingForCustomConverter customConverter = new ConvertCheckingForCustomConverter ();
customConverter . tryfirstConverter = valueDependentConversion ;
customConverter . fallbackConverter = converter ;
converter = customConverter . Convert ;
if ( valueDependentRank > rank )
{
rank = valueDependentRank ;
}
else if ( rank == ConversionRank . None )
{
rank = ConversionRank . Custom ;
}
}
else if ( valueDependentConversion != null )
{
converter = valueDependentConversion ;
rank = valueDependentRank ;
}
if ( converter == null )
{
converter = ConvertNoConversion ;
rank = ConversionRank . None ;
}
return CacheConversion ( fromType , toType , converter , rank );
}
internal class Null { };
private static ConversionData FigureConversionFromNull ( Type toType )
{
ConversionData data = GetConversionData ( typeof ( Null ), toType );
if ( data != null )
{
return data ;
}
if ( Nullable . GetUnderlyingType ( toType ) != null )
{
return CacheConversion < object >( typeof ( Null ), toType , LanguagePrimitives . ConvertNullToNullable , ConversionRank . NullToValue );
}
else if (! toType . GetTypeInfo (). IsValueType )
{
return CacheConversion < object >( typeof ( Null ), toType , LanguagePrimitives . ConvertNullToRef , ConversionRank . NullToRef );
}
return CacheConversion ( typeof ( Null ), toType , ConvertNoConversion , ConversionRank . None );
}
internal static string ObjectToTypeNameString ( object o )
{
if ( o == null )
{
return "null" ;
}
PSObject pso = PSObject . AsPSObject ( o );
var typeNames = pso . InternalTypeNames ;
if (( typeNames != null ) && ( typeNames . Count > 0 ))
{
return typeNames [ 0 ];
}
return Microsoft . PowerShell . ToStringCodeMethods . Type ( o . GetType ());
}
#if ! CORECLR // AppDomain Not In CoreCLR
static Assembly AssemblyResolveHelper ( object sender , ResolveEventArgs args )
{
// Dynamic assemblies don't get resolved properly by the CLR, so we
// resolve them ourselves by looking through the loaded assemblies.
foreach ( Assembly assem in ClrFacade . GetAssemblies ())
{
if ( assem . FullName == args . Name )
{
return assem ;
}
}
return null ;
}
#endif
#endregion type converter
}
}
#pragma warning restore 56500