@@ -58,7 +58,28 @@ public INamedTypeSymbol Get(SpecialType type)
58
58
return _compilation . GetSpecialType ( type ) ;
59
59
}
60
60
61
+ /// <summary>
62
+ /// Returns the type symbol for the specified well-known type, or throws if the type cannot be found.
63
+ /// </summary>
61
64
public INamedTypeSymbol Get ( WellKnownTypeData . WellKnownType type )
65
+ {
66
+ return Get ( type , throwOnNotFound : true ) ;
67
+ }
68
+
69
+ /// <summary>
70
+ /// Returns the type symbol for the specified well-known type, or a special marker type symbol if the type cannot be found.
71
+ /// </summary>
72
+ /// <remarks>
73
+ /// We use a special marker type for cases where some types can be legitimately missing.
74
+ /// E.g. The Microsoft.Extensions.Validation source generator checks against some types
75
+ /// from the shared framework which are missing in Blazor WebAssembly SDK projects.
76
+ /// </remarks>
77
+ public INamedTypeSymbol GetOptional ( WellKnownTypeData . WellKnownType type )
78
+ {
79
+ return Get ( type , throwOnNotFound : false ) ;
80
+ }
81
+
82
+ private INamedTypeSymbol Get ( WellKnownTypeData . WellKnownType type , bool throwOnNotFound )
62
83
{
63
84
var index = ( int ) type ;
64
85
var symbol = _lazyWellKnownTypes [ index ] ;
@@ -69,16 +90,22 @@ public INamedTypeSymbol Get(WellKnownTypeData.WellKnownType type)
69
90
70
91
// Symbol hasn't been added to the cache yet.
71
92
// Resolve symbol from name, cache, and return.
72
- return GetAndCache ( index ) ;
93
+ return GetAndCache ( index , throwOnNotFound ) ;
73
94
}
74
95
75
- private INamedTypeSymbol GetAndCache ( int index )
96
+ private INamedTypeSymbol GetAndCache ( int index , bool throwOnNotFound )
76
97
{
77
98
var result = GetTypeByMetadataNameInTargetAssembly ( WellKnownTypeData . WellKnownTypeNames [ index ] ) ;
78
- if ( result == null )
99
+
100
+ if ( result == null && throwOnNotFound )
79
101
{
80
102
throw new InvalidOperationException ( $ "Failed to resolve well-known type '{ WellKnownTypeData . WellKnownTypeNames [ index ] } '.") ;
81
103
}
104
+ else
105
+ {
106
+ result ??= _compilation . GetTypeByMetadataName ( typeof ( MissingType ) . FullName ! ) ! ;
107
+ }
108
+
82
109
Interlocked . CompareExchange ( ref _lazyWellKnownTypes [ index ] , result , null ) ;
83
110
84
111
// GetTypeByMetadataName should always return the same instance for a name.
@@ -159,4 +186,6 @@ public static bool Implements(ITypeSymbol? type, ITypeSymbol interfaceType)
159
186
}
160
187
return false ;
161
188
}
189
+
190
+ internal class MissingType { }
162
191
}
0 commit comments