in packages/jsii-pacmak/lib/targets/dotnet/runtime-type-checking.ts [164:269]
public emit(code: CodeMaker, resolver: DotNetTypeResolver): void {
const validTypes = new Array<string>();
const castVarName = `cast_${createHash('sha256')
.update(expression)
.digest('hex')
.slice(0, 6)}`;
code.openBlock(`switch (${expression})`);
for (const type of types) {
validTypes.push(resolver.toDotNetTypeName(type.spec!));
/**
* Filter to remove classes and interfaces from a set of type references that
* are implied by another entry in the set. Practically this is meant to remove
* types from a set if a parent type of it is also present in the set, keeping
* only the most generic declaration.
*
* This is useful because the TypeScript compiler and jsii do not guarantee that
* all entries in a type union are unrelated, but the C# compiler treats dead
* code as an error, and will refuse to compile (error CS8120) a pattern-matching
* switch case if it cannot be matched (for example, if it matches on a child of
* a type that was previously matched on already).
*/
if (
(type.type?.isClassType() || type.type?.isInterfaceType()) &&
types.some(
(other) =>
other !== type &&
other.type != null &&
type.type!.extends(other.type),
)
) {
continue;
}
const typeNames = [resolver.toDotNetType(type.spec!)];
if (typeNames[0] === 'double') {
// For doubles, we accept any numeric value, really...
typeNames.push(
'byte',
'decimal',
'float',
'int',
'long',
'sbyte',
'short',
'uint',
'ulong',
'ushort',
);
}
for (const typeName of typeNames) {
code.indent(`case ${typeName} ${castVarName}:`);
Validation.forTypeReference(
argument,
castVarName,
description,
type,
allowNull,
)?.emit(code, resolver);
code.line('break;');
code.unindent(false);
}
}
if (hasInterface) {
code.indent(
`case Amazon.JSII.Runtime.Deputy.AnonymousObject ${castVarName}:`,
);
code.line('// Not enough information to type-check...');
code.line('break;');
code.unindent(false);
}
code.indent('case null:');
const acceptedTypes = validTypes
.map((t) =>
t.startsWith('"')
? t.slice(1, t.length - 1)
: t.startsWith('$"')
? t.slice(2, t.length - 1)
: `{${t}}`,
)
.join(', ');
if (allowNull) {
code.line('break;');
} else {
const message = JSON.stringify(
`Expected ${description} to be one of: ${acceptedTypes}; received null`,
);
code.line(
`throw new System.ArgumentException($${message}, ${argument});`,
);
}
code.unindent(false);
code.indent('default:');
const message = JSON.stringify(
`Expected ${description} to be one of: ${acceptedTypes}; received {${expression}.GetType().FullName}`,
);
code.line(
`throw new System.ArgumentException($${message}, ${argument});`,
);
code.unindent(false);
code.closeBlock();
}