internal static object?CheckArgument(object?srcObject, EETypePtr dstEEType, CheckArgumentSemantics semantics, BinderBundle?binderBundle) { // Methods with ByRefLike types in signatures should be filtered out earlier Debug.Assert(!dstEEType.IsByRefLike); if (srcObject == null) { // null -> default(T) if (dstEEType.IsPointer) { return(default(IntPtr)); } else if (dstEEType.IsValueType && !dstEEType.IsNullable) { if (semantics == CheckArgumentSemantics.SetFieldDirect) { throw CreateChangeTypeException(typeof(object).TypeHandle.ToEETypePtr(), dstEEType, semantics); } return(Runtime.RuntimeImports.RhNewObject(dstEEType)); } else { return(null); } } else { EETypePtr srcEEType = srcObject.GetEETypePtr(); if (srcEEType.RawValue == dstEEType.RawValue || RuntimeImports.AreTypesAssignable(srcEEType, dstEEType) || (dstEEType.IsInterface && srcObject is Runtime.InteropServices.IDynamicInterfaceCastable castable && castable.IsInterfaceImplemented(new RuntimeTypeHandle(dstEEType), throwIfNotImplemented: false))) { return(srcObject); } return(CheckArgumentConversions(srcObject, dstEEType, semantics, binderBundle)); } }
internal static Object CheckArgument(Object srcObject, EETypePtr dstEEType, CheckArgumentSemantics semantics, BinderBundle binderBundle, Func <Type> getExactTypeForCustomBinder = null) { if (srcObject == null) { // null -> default(T) if (dstEEType.IsValueType && !dstEEType.IsNullable) { if (semantics == CheckArgumentSemantics.SetFieldDirect) { throw CreateChangeTypeException(CommonRuntimeTypes.Object.TypeHandle.ToEETypePtr(), dstEEType, semantics); } return(Runtime.RuntimeImports.RhNewObject(dstEEType)); } else { return(null); } } else { EETypePtr srcEEType = srcObject.EETypePtr; if (RuntimeImports.AreTypesAssignable(srcEEType, dstEEType)) { return(srcObject); } if (dstEEType.IsInterface) { ICastable castable = srcObject as ICastable; Exception castError; if (castable != null && castable.IsInstanceOfInterface(new RuntimeTypeHandle(dstEEType), out castError)) { return(srcObject); } } object dstObject; Exception exception = ConvertOrWidenPrimitivesEnumsAndPointersIfPossible(srcObject, srcEEType, dstEEType, semantics, out dstObject); if (exception == null) { return(dstObject); } if (binderBundle == null) { throw exception; } // Our normal coercion rules could not convert the passed in argument but we were supplied a custom binder. See if it can do it. Type exactDstType; if (getExactTypeForCustomBinder == null) { // We were called by someone other than DynamicInvokeParamHelperCore(). Those callers pass the correct dstEEType. exactDstType = Type.GetTypeFromHandle(new RuntimeTypeHandle(dstEEType)); } else { // We were called by DynamicInvokeParamHelperCore(). He passes a dstEEType that enums folded to int and possibly other adjustments. A custom binder // is app code however and needs the exact type. exactDstType = getExactTypeForCustomBinder(); } srcObject = binderBundle.ChangeType(srcObject, exactDstType); // For compat with desktop, the result of the binder call gets processed through the default rules again. dstObject = CheckArgument(srcObject, dstEEType, semantics, binderBundle: null, getExactTypeForCustomBinder: null); return(dstObject); } }
private static Exception CreateChangeTypeException(EETypePtr srcEEType, EETypePtr dstEEType, CheckArgumentSemantics semantics) { switch (semantics) { case CheckArgumentSemantics.DynamicInvoke: case CheckArgumentSemantics.SetFieldDirect: return(CreateChangeTypeArgumentException(srcEEType, dstEEType)); case CheckArgumentSemantics.ArraySet: return(CreateChangeTypeInvalidCastException(srcEEType, dstEEType)); default: Debug.Fail("Unexpected CheckArgumentSemantics value: " + semantics); throw new InvalidOperationException(); } }
private static Exception ConvertPointerIfPossible(object srcObject, EETypePtr srcEEType, EETypePtr dstEEType, CheckArgumentSemantics semantics, out IntPtr dstIntPtr) { if (srcObject is IntPtr srcIntPtr) { dstIntPtr = srcIntPtr; return(null); } if (srcObject is Pointer srcPointer) { if (dstEEType == typeof(void *).TypeHandle.ToEETypePtr() || RuntimeImports.AreTypesAssignable(pSourceType: srcPointer.GetPointerType().TypeHandle.ToEETypePtr(), pTargetType: dstEEType)) { dstIntPtr = srcPointer.GetPointerValue(); return(null); } } dstIntPtr = IntPtr.Zero; return(CreateChangeTypeException(srcEEType, dstEEType, semantics)); }
// Special coersion rules for primitives, enums and pointer. private static Exception ConvertOrWidenPrimitivesEnumsAndPointersIfPossible(object srcObject, EETypePtr srcEEType, EETypePtr dstEEType, CheckArgumentSemantics semantics, out object dstObject) { if (semantics == CheckArgumentSemantics.SetFieldDirect && (srcEEType.IsEnum || dstEEType.IsEnum)) { dstObject = null; return(CreateChangeTypeException(srcEEType, dstEEType, semantics)); } if (dstEEType.IsPointer) { Exception exception = ConvertPointerIfPossible(srcObject, srcEEType, dstEEType, semantics, out IntPtr dstIntPtr); if (exception != null) { dstObject = null; return(exception); } dstObject = dstIntPtr; return(null); } if (!(srcEEType.IsPrimitive && dstEEType.IsPrimitive)) { dstObject = null; return(CreateChangeTypeException(srcEEType, dstEEType, semantics)); } RuntimeImports.RhCorElementType dstCorElementType = dstEEType.CorElementType; if (!srcEEType.CorElementTypeInfo.CanWidenTo(dstCorElementType)) { dstObject = null; return(CreateChangeTypeArgumentException(srcEEType, dstEEType)); } switch (dstCorElementType) { case RuntimeImports.RhCorElementType.ELEMENT_TYPE_BOOLEAN: bool boolValue = Convert.ToBoolean(srcObject); dstObject = dstEEType.IsEnum ? Enum.ToObject(dstEEType, boolValue ? 1 : 0) : boolValue; break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_CHAR: char charValue = Convert.ToChar(srcObject); dstObject = dstEEType.IsEnum ? Enum.ToObject(dstEEType, charValue) : charValue; break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_I1: sbyte sbyteValue = Convert.ToSByte(srcObject); dstObject = dstEEType.IsEnum ? Enum.ToObject(dstEEType, sbyteValue) : sbyteValue; break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_I2: short shortValue = Convert.ToInt16(srcObject); dstObject = dstEEType.IsEnum ? Enum.ToObject(dstEEType, shortValue) : shortValue; break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_I4: int intValue = Convert.ToInt32(srcObject); dstObject = dstEEType.IsEnum ? Enum.ToObject(dstEEType, intValue) : intValue; break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_I8: long longValue = Convert.ToInt64(srcObject); dstObject = dstEEType.IsEnum ? Enum.ToObject(dstEEType, longValue) : longValue; break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_U1: byte byteValue = Convert.ToByte(srcObject); dstObject = dstEEType.IsEnum ? Enum.ToObject(dstEEType, byteValue) : byteValue; break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_U2: ushort ushortValue = Convert.ToUInt16(srcObject); dstObject = dstEEType.IsEnum ? Enum.ToObject(dstEEType, ushortValue) : ushortValue; break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_U4: uint uintValue = Convert.ToUInt32(srcObject); dstObject = dstEEType.IsEnum ? Enum.ToObject(dstEEType, uintValue) : uintValue; break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_U8: ulong ulongValue = Convert.ToUInt64(srcObject); dstObject = dstEEType.IsEnum ? Enum.ToObject(dstEEType, (long)ulongValue) : ulongValue; break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_R4: if (srcEEType.CorElementType == RuntimeImports.RhCorElementType.ELEMENT_TYPE_CHAR) { dstObject = (float)(char)srcObject; } else { dstObject = Convert.ToSingle(srcObject); } break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_R8: if (srcEEType.CorElementType == RuntimeImports.RhCorElementType.ELEMENT_TYPE_CHAR) { dstObject = (double)(char)srcObject; } else { dstObject = Convert.ToDouble(srcObject); } break; default: Debug.Fail("Unexpected CorElementType: " + dstCorElementType + ": Not a valid widening target."); dstObject = null; return(CreateChangeTypeException(srcEEType, dstEEType, semantics)); } Debug.Assert(dstObject.EETypePtr == dstEEType); return(null); }
internal static object?CheckArgument(object?srcObject, EETypePtr dstEEType, CheckArgumentSemantics semantics, BinderBundle?binderBundle, ref ArgSetupState argSetupState) { // Methods with ByRefLike types in signatures should be filtered out by the compiler Debug.Assert(!dstEEType.IsByRefLike); if (srcObject == null) { // null -> default(T) if (dstEEType.IsPointer) { return(default(IntPtr)); } else if (dstEEType.IsValueType && !dstEEType.IsNullable) { if (semantics == CheckArgumentSemantics.SetFieldDirect) { throw CreateChangeTypeException(typeof(object).TypeHandle.ToEETypePtr(), dstEEType, semantics); } return(Runtime.RuntimeImports.RhNewObject(dstEEType)); } else { return(null); } } else { EETypePtr srcEEType = srcObject.EETypePtr; if (RuntimeImports.AreTypesAssignable(srcEEType, dstEEType)) { return(srcObject); } if (dstEEType.IsInterface) { if (srcObject is Runtime.InteropServices.IDynamicInterfaceCastable castable && castable.IsInterfaceImplemented(new RuntimeTypeHandle(dstEEType), throwIfNotImplemented: false)) { return(srcObject); } } object dstObject; Exception exception = ConvertOrWidenPrimitivesEnumsAndPointersIfPossible(srcObject, srcEEType, dstEEType, semantics, out dstObject); if (exception == null) { return(dstObject); } if (binderBundle == null) { throw exception; } // Our normal coercion rules could not convert the passed in argument but we were supplied a custom binder. See if it can do it. Type exactDstType; if (Unsafe.IsNullRef(ref argSetupState)) { // We were called by someone other than DynamicInvokeParamHelperCore(). Those callers pass the correct dstEEType. exactDstType = Type.GetTypeFromHandle(new RuntimeTypeHandle(dstEEType)) !; } else { // We were called by DynamicInvokeParamHelperCore(). He passes a dstEEType that enums folded to int and possibly other adjustments. A custom binder // is app code however and needs the exact type. exactDstType = GetExactTypeForCustomBinder(argSetupState); } srcObject = binderBundle.ChangeType(srcObject, exactDstType); // For compat with desktop, the result of the binder call gets processed through the default rules again. dstObject = CheckArgument(srcObject, dstEEType, semantics, binderBundle: null, ref Unsafe.NullRef <ArgSetupState>()); return(dstObject); } }
internal static object?CheckArgument(object?srcObject, EETypePtr dstEEType, CheckArgumentSemantics semantics, BinderBundle?binderBundle) { return(CheckArgument(srcObject, dstEEType, semantics, binderBundle, ref Unsafe.NullRef <ArgSetupState>())); }
// Special coersion rules for primitives, enums and pointer. private static Exception ConvertOrWidenPrimitivesEnumsAndPointersIfPossible(object srcObject, EETypePtr srcEEType, EETypePtr dstEEType, CheckArgumentSemantics semantics, out object dstObject) { if (semantics == CheckArgumentSemantics.SetFieldDirect && (srcEEType.IsEnum || dstEEType.IsEnum)) { dstObject = null; return(CreateChangeTypeException(srcEEType, dstEEType, semantics)); } if (dstEEType.IsPointer) { Exception exception = ConvertPointerIfPossible(srcObject, srcEEType, dstEEType, semantics, out IntPtr dstIntPtr); if (exception != null) { dstObject = null; return(exception); } dstObject = dstIntPtr; return(null); } if (!(srcEEType.IsPrimitive && dstEEType.IsPrimitive)) { dstObject = null; return(CreateChangeTypeException(srcEEType, dstEEType, semantics)); } RuntimeImports.RhCorElementType dstCorElementType = dstEEType.CorElementType; if (!srcEEType.CorElementTypeInfo.CanWidenTo(dstCorElementType)) { dstObject = null; return(CreateChangeTypeArgumentException(srcEEType, dstEEType)); } switch (dstCorElementType) { case RuntimeImports.RhCorElementType.ELEMENT_TYPE_BOOLEAN: dstObject = Convert.ToBoolean(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_CHAR: dstObject = Convert.ToChar(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_I1: dstObject = Convert.ToSByte(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_I2: dstObject = Convert.ToInt16(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_I4: dstObject = Convert.ToInt32(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_I8: dstObject = Convert.ToInt64(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_U1: dstObject = Convert.ToByte(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_U2: dstObject = Convert.ToUInt16(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_U4: dstObject = Convert.ToUInt32(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_U8: dstObject = Convert.ToUInt64(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_R4: if (srcEEType.CorElementType == RuntimeImports.RhCorElementType.ELEMENT_TYPE_CHAR) { dstObject = (float)(char)srcObject; } else { dstObject = Convert.ToSingle(srcObject); } break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_R8: if (srcEEType.CorElementType == RuntimeImports.RhCorElementType.ELEMENT_TYPE_CHAR) { dstObject = (double)(char)srcObject; } else { dstObject = Convert.ToDouble(srcObject); } break; default: Debug.Assert(false, "Unexpected CorElementType: " + dstCorElementType + ": Not a valid widening target."); dstObject = null; return(CreateChangeTypeException(srcEEType, dstEEType, semantics)); } if (dstEEType.IsEnum) { Type dstType = ReflectionCoreNonPortable.GetRuntimeTypeForEEType(dstEEType); dstObject = Enum.ToObject(dstType, dstObject); } Debug.Assert(dstObject.EETypePtr == dstEEType); return(null); }
internal static Object CheckArgument(Object srcObject, EETypePtr dstEEType, CheckArgumentSemantics semantics) { if (srcObject == null) { // null -> default(T) if (dstEEType.IsValueType && !RuntimeImports.RhIsNullable(dstEEType)) return Runtime.RuntimeImports.RhNewObject(dstEEType); else return null; } else { EETypePtr srcEEType = srcObject.EETypePtr; if (RuntimeImports.AreTypesAssignable(srcEEType, dstEEType)) return srcObject; if (RuntimeImports.RhIsInterface(dstEEType)) { ICastable castable = srcObject as ICastable; Exception castError; if (castable != null && castable.IsInstanceOfInterface(new RuntimeTypeHandle(dstEEType), out castError)) return srcObject; } if (!((srcEEType.IsEnum || srcEEType.IsPrimitive) && (dstEEType.IsEnum || dstEEType.IsPrimitive))) throw CreateChangeTypeException(srcEEType, dstEEType, semantics); RuntimeImports.RhCorElementType dstCorElementType = dstEEType.CorElementType; if (!srcEEType.CorElementTypeInfo.CanWidenTo(dstCorElementType)) throw CreateChangeTypeArgumentException(srcEEType, dstEEType); Object dstObject; switch (dstCorElementType) { case RuntimeImports.RhCorElementType.ELEMENT_TYPE_BOOLEAN: dstObject = Convert.ToBoolean(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_CHAR: dstObject = Convert.ToChar(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_I1: dstObject = Convert.ToSByte(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_I2: dstObject = Convert.ToInt16(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_I4: dstObject = Convert.ToInt32(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_I8: dstObject = Convert.ToInt64(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_U1: dstObject = Convert.ToByte(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_U2: dstObject = Convert.ToUInt16(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_U4: dstObject = Convert.ToUInt32(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_U8: dstObject = Convert.ToUInt64(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_R4: if (srcEEType.CorElementType == RuntimeImports.RhCorElementType.ELEMENT_TYPE_CHAR) { dstObject = (float)(char)srcObject; } else { dstObject = Convert.ToSingle(srcObject); } break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_R8: if (srcEEType.CorElementType == RuntimeImports.RhCorElementType.ELEMENT_TYPE_CHAR) { dstObject = (double)(char)srcObject; } else { dstObject = Convert.ToDouble(srcObject); } break; default: Debug.Assert(false, "Unexpected CorElementType: " + dstCorElementType + ": Not a valid widening target."); throw CreateChangeTypeException(srcEEType, dstEEType, semantics); } if (dstEEType.IsEnum) { Type dstType = ReflectionCoreNonPortable.GetRuntimeTypeForEEType(dstEEType); dstObject = Enum.ToObject(dstType, dstObject); } Debug.Assert(dstObject.EETypePtr == dstEEType); return dstObject; } }
private static Exception CreateChangeTypeException(EETypePtr srcEEType, EETypePtr dstEEType, CheckArgumentSemantics semantics) { switch (semantics) { case CheckArgumentSemantics.DynamicInvoke: return CreateChangeTypeArgumentException(srcEEType, dstEEType); case CheckArgumentSemantics.ArraySet: return CreateChangeTypeInvalidCastException(srcEEType, dstEEType); default: Debug.Assert(false, "Unexpected CheckArgumentSemantics value: " + semantics); throw new InvalidOperationException(); } }
internal static Object CheckArgument(Object srcObject, EETypePtr dstEEType, CheckArgumentSemantics semantics) { if (srcObject == null) { // null -> default(T) if (dstEEType.IsValueType && !dstEEType.IsNullable) { return(Runtime.RuntimeImports.RhNewObject(dstEEType)); } else { return(null); } } else { EETypePtr srcEEType = srcObject.EETypePtr; if (RuntimeImports.AreTypesAssignable(srcEEType, dstEEType)) { return(srcObject); } if (dstEEType.IsInterface) { ICastable castable = srcObject as ICastable; Exception castError; if (castable != null && castable.IsInstanceOfInterface(new RuntimeTypeHandle(dstEEType), out castError)) { return(srcObject); } } if (!((srcEEType.IsEnum || srcEEType.IsPrimitive) && (dstEEType.IsEnum || dstEEType.IsPrimitive))) { throw CreateChangeTypeException(srcEEType, dstEEType, semantics); } RuntimeImports.RhCorElementType dstCorElementType = dstEEType.CorElementType; if (!srcEEType.CorElementTypeInfo.CanWidenTo(dstCorElementType)) { throw CreateChangeTypeArgumentException(srcEEType, dstEEType); } Object dstObject; switch (dstCorElementType) { case RuntimeImports.RhCorElementType.ELEMENT_TYPE_BOOLEAN: dstObject = Convert.ToBoolean(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_CHAR: dstObject = Convert.ToChar(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_I1: dstObject = Convert.ToSByte(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_I2: dstObject = Convert.ToInt16(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_I4: dstObject = Convert.ToInt32(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_I8: dstObject = Convert.ToInt64(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_U1: dstObject = Convert.ToByte(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_U2: dstObject = Convert.ToUInt16(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_U4: dstObject = Convert.ToUInt32(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_U8: dstObject = Convert.ToUInt64(srcObject); break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_R4: if (srcEEType.CorElementType == RuntimeImports.RhCorElementType.ELEMENT_TYPE_CHAR) { dstObject = (float)(char)srcObject; } else { dstObject = Convert.ToSingle(srcObject); } break; case RuntimeImports.RhCorElementType.ELEMENT_TYPE_R8: if (srcEEType.CorElementType == RuntimeImports.RhCorElementType.ELEMENT_TYPE_CHAR) { dstObject = (double)(char)srcObject; } else { dstObject = Convert.ToDouble(srcObject); } break; default: Debug.Assert(false, "Unexpected CorElementType: " + dstCorElementType + ": Not a valid widening target."); throw CreateChangeTypeException(srcEEType, dstEEType, semantics); } if (dstEEType.IsEnum) { Type dstType = ReflectionCoreNonPortable.GetRuntimeTypeForEEType(dstEEType); dstObject = Enum.ToObject(dstType, dstObject); } Debug.Assert(dstObject.EETypePtr == dstEEType); return(dstObject); } }
internal static object?CheckArgumentConversions(object srcObject, EETypePtr dstEEType, CheckArgumentSemantics semantics, BinderBundle?binderBundle) { object? dstObject; Exception exception = ConvertOrWidenPrimitivesEnumsAndPointersIfPossible(srcObject, dstEEType, semantics, out dstObject); if (exception == null) { return(dstObject); } if (binderBundle == null) { throw exception; } // Our normal coercion rules could not convert the passed in argument but we were supplied a custom binder. See if it can do it. Type exactDstType = Type.GetTypeFromHandle(new RuntimeTypeHandle(dstEEType)) !; srcObject = binderBundle.ChangeType(srcObject, exactDstType); // For compat with desktop, the result of the binder call gets processed through the default rules again. return(CheckArgument(srcObject, dstEEType, semantics, binderBundle: null)); }