7
7
8
8
namespace YamlDotNet . Serialization . BufferedDeserialization . TypeDiscriminators
9
9
{
10
+ /// <summary>
11
+ /// A TypeDiscriminator that discriminates which type to deserialize a yaml stream into by checking the value
12
+ /// of a known key.
13
+ /// </summary>
10
14
public class KeyValueTypeDiscriminator : ITypeDiscriminator
11
15
{
12
16
public Type BaseType { get ; private set ; }
13
17
private readonly string targetKey ;
14
18
private readonly IDictionary < string , Type > typeMapping ;
15
19
20
+ /// <summary>
21
+ /// Initializes a new instance of the <see cref="KeyValueTypeDiscriminator"/> class.
22
+ /// The KeyValueTypeDiscriminator will check the target key specified, and if it's value is contained within the
23
+ /// type mapping dictionary, the coresponding type will be discriminated.
24
+ /// </summary>
25
+ /// <param name="baseType">The base type which all discriminated types will implement. Use object if you're discriminating
26
+ /// unrelated types. Note the less specific you are with the base type the more yaml will need to be buffered.</param>
27
+ /// <param name="targetKey">The known key to check the value of when discriminating.</param>
28
+ /// <param name="typeMapping">A mapping dictionary of string to types.</param>
29
+ /// <exception cref="ArgumentOutOfRangeException">If any of the target types do not implement the base type.</exception>
16
30
public KeyValueTypeDiscriminator ( Type baseType , string targetKey , IDictionary < string , Type > typeMapping )
17
31
{
18
-
19
32
foreach ( var keyValuePair in typeMapping )
20
33
{
21
34
if ( ! baseType . IsAssignableFrom ( keyValuePair . Value ) )
@@ -28,6 +41,17 @@ public KeyValueTypeDiscriminator(Type baseType, string targetKey, IDictionary<st
28
41
this . typeMapping = typeMapping ;
29
42
}
30
43
44
+ /// <summary>
45
+ /// Checks if the current parser contains the target key, and that it's value matches one of the type mappings.
46
+ /// If so, return true, and the matching type.
47
+ /// Otherwise, return false.
48
+ /// This will consume the parser, so you will usually need the parser to be a buffer so an instance
49
+ /// of the discriminated type can be deserialized later.
50
+ /// </summary>
51
+ /// <param name="parser">The IParser to consume and discriminate a type from.</param>
52
+ /// <param name="suggestedType">The output type discriminated. Null if there target key was not present of if the value
53
+ /// of the target key was not within the type mapping.</param>
54
+ /// <returns>Returns true if the discriminator matched the yaml stream.</returns>
31
55
public bool TryDiscriminate ( IParser parser , out Type ? suggestedType )
32
56
{
33
57
if ( parser . TryFindMappingEntry (
@@ -36,32 +60,16 @@ public bool TryDiscriminate(IParser parser, out Type? suggestedType)
36
60
out ParsingEvent ? value ) )
37
61
{
38
62
// read the value of the discriminator key
39
- if ( value is Scalar valueScalar )
63
+ if ( value is Scalar valueScalar && typeMapping . TryGetValue ( valueScalar . Value , out var childType ) )
40
64
{
41
- suggestedType = CheckName ( valueScalar . Value ) ;
65
+ suggestedType = childType ;
42
66
return true ;
43
67
}
44
- else
45
- {
46
- throw new Exception ( $ "Could not determine { BaseType } to deserialize to, { targetKey } has an empty value") ;
47
- }
48
68
}
49
69
50
70
// we could not find our key, thus we could not determine correct child type
51
71
suggestedType = null ;
52
72
return false ;
53
73
}
54
-
55
- private Type CheckName ( string value )
56
- {
57
- if ( typeMapping . TryGetValue ( value , out var childType ) )
58
- {
59
- return childType ;
60
- }
61
-
62
- var known = string . Join ( "," , typeMapping . Keys . ToArray ( ) ) ;
63
-
64
- throw new Exception ( $ "Could not determine { BaseType } to deserialize to, expecting '{ targetKey } ' to be one of: { known } , but got '{ value } '") ;
65
- }
66
74
}
67
75
}
0 commit comments