77
88namespace YamlDotNet . Serialization . BufferedDeserialization . TypeDiscriminators
99{
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>
1014 public class KeyValueTypeDiscriminator : ITypeDiscriminator
1115 {
1216 public Type BaseType { get ; private set ; }
1317 private readonly string targetKey ;
1418 private readonly IDictionary < string , Type > typeMapping ;
1519
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>
1630 public KeyValueTypeDiscriminator ( Type baseType , string targetKey , IDictionary < string , Type > typeMapping )
1731 {
18-
1932 foreach ( var keyValuePair in typeMapping )
2033 {
2134 if ( ! baseType . IsAssignableFrom ( keyValuePair . Value ) )
@@ -28,6 +41,17 @@ public KeyValueTypeDiscriminator(Type baseType, string targetKey, IDictionary<st
2841 this . typeMapping = typeMapping ;
2942 }
3043
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>
3155 public bool TryDiscriminate ( IParser parser , out Type ? suggestedType )
3256 {
3357 if ( parser . TryFindMappingEntry (
@@ -36,32 +60,16 @@ public bool TryDiscriminate(IParser parser, out Type? suggestedType)
3660 out ParsingEvent ? value ) )
3761 {
3862 // 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 ) )
4064 {
41- suggestedType = CheckName ( valueScalar . Value ) ;
65+ suggestedType = childType ;
4266 return true ;
4367 }
44- else
45- {
46- throw new Exception ( $ "Could not determine { BaseType } to deserialize to, { targetKey } has an empty value") ;
47- }
4868 }
4969
5070 // we could not find our key, thus we could not determine correct child type
5171 suggestedType = null ;
5272 return false ;
5373 }
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- }
6674 }
6775}
0 commit comments