Skip to content

Commit fc856a2

Browse files
authored
GetType: keep throwing same exceptions as .NET 8 (#114228)
When using Type.GetType, always throw FileLoadException for invalid assembly names no matter what throwOnError is set to. When using Assembly.GetType, throw only when throwOnError is set, and ArgumentException (not FileLoadException) Fixes #113534
1 parent 39265ca commit fc856a2

File tree

4 files changed

+29
-7
lines changed

4 files changed

+29
-7
lines changed

Diff for: src/coreclr/System.Private.CoreLib/src/System/Reflection/TypeNameResolver.CoreCLR.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -80,13 +80,13 @@ internal partial struct TypeNameResolver
8080
bool ignoreCase,
8181
Assembly topLevelAssembly)
8282
{
83-
TypeName? parsed = TypeNameParser.Parse(typeName, throwOnError);
83+
TypeName? parsed = TypeNameParser.Parse(typeName, throwOnError, new() { IsAssemblyGetType = true });
8484

8585
if (parsed is null)
8686
{
8787
return null;
8888
}
89-
else if (topLevelAssembly is not null && parsed.AssemblyName is not null)
89+
else if (parsed.AssemblyName is not null)
9090
{
9191
return throwOnError ? throw new ArgumentException(SR.Argument_AssemblyGetTypeCannotSpecifyAssembly) : null;
9292
}

Diff for: src/libraries/System.Private.CoreLib/src/System/Reflection/TypeNameResolver.cs

+2
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ public int MaxNodes
2020
}
2121
}
2222
#pragma warning restore CA1822
23+
24+
internal bool IsAssemblyGetType { get; set; }
2325
}
2426
}
2527

Diff for: src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/TypeNameParser.cs

+14-4
Original file line numberDiff line numberDiff line change
@@ -188,14 +188,24 @@ private TypeNameParser(ReadOnlySpan<char> name, bool throwOnError, TypeNameParse
188188
if (allowFullyQualifiedName && !TryParseAssemblyName(ref assemblyName))
189189
{
190190
#if SYSTEM_PRIVATE_CORELIB
191-
// backward compat: throw FileLoadException for non-empty invalid strings
192-
if (_throwOnError || !_inputString.TrimStart().StartsWith(","))
191+
// Backward compatibility: throw for non-empty invalid assembly names.
192+
if (!_inputString.TrimStart().StartsWith(","))
193193
{
194+
// Reject attempt to provide top-level assembly name to Assembly.GetType
195+
if (_parseOptions.IsAssemblyGetType)
196+
{
197+
if (_throwOnError)
198+
{
199+
throw new ArgumentException(SR.Argument_AssemblyGetTypeCannotSpecifyAssembly);
200+
}
201+
return null;
202+
}
203+
204+
// Otherwise, no matter what throwOnError is set to, we throw FileLoadException for invalid assembly names.
194205
throw new IO.FileLoadException(SR.InvalidAssemblyName, _inputString.ToString());
195206
}
196-
#else
197-
return null;
198207
#endif
208+
return null;
199209
}
200210

201211
// No matter what was parsed, the full name string is allocated only once.

Diff for: src/libraries/System.Runtime/tests/System.Reflection.Tests/GetTypeTests.cs

+11-1
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ public void GetType_CoreAssembly()
276276
{
277277
Assert.Equal(typeof(int), Type.GetType("System.Int32", throwOnError: true));
278278
Assert.Equal(typeof(int), Type.GetType("system.int32", throwOnError: true, ignoreCase: true));
279+
Assert.Null(typeof(int).Assembly.GetType("a,b", throwOnError: false, ignoreCase: false));
280+
Assert.Null(typeof(int).Assembly.GetType("a,b,c", throwOnError: false, ignoreCase: false));
279281
}
280282

281283
[Fact]
@@ -294,7 +296,15 @@ public void GetType_InvalidAssemblyName()
294296
Assert.Null(Type.GetType("MissingAssemblyName, "));
295297
Assert.Null(Type.GetType("ExtraComma, ,"));
296298
Assert.Null(Type.GetType("ExtraComma, , System.Runtime"));
297-
Assert.Throws<FileLoadException>(() => Type.GetType("System.Object, System.Runtime, Version=x.y"));
299+
300+
// Backward compat: no matter what throwOnError is set to, CLR throws FileLoadException for invalid assembly names.
301+
Assert.Throws<FileLoadException>(() => Type.GetType("System.Object, System.Runtime, Version=x.y", throwOnError: false));
302+
Assert.Throws<FileLoadException>(() => Type.GetType("System.Object, System.Runtime, Version=x.y", throwOnError: true));
303+
304+
// Backward compat: when using Assembly.GetType, throwOnError is not ignored and ArgumentException can be thrown.
305+
Assembly coreLib = typeof(int).Assembly;
306+
Assert.Null(coreLib.GetType("System.Object, System.Runtime, Version=x.y", throwOnError: false));
307+
Assert.Throws<ArgumentException>(() => coreLib.GetType("System.Object, System.Runtime, Version=x.y", throwOnError: true));
298308
}
299309

300310
[ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsTypeEquivalenceSupported))]

0 commit comments

Comments
 (0)