The following example shows Type.GetType failing in a specific scenario.
GetType succeeds when I provide it the class name string (including namespace) in a lambda expression, but fails when I specify the call to GetType as a method group.
Fails:
collectionOfClassNames.Select(GetType)
Succeeds:
collectionOfClassNames.Select(s => GetType(s))
Both methods succeed when the class path includes the assembly name. I suspect it's something to do with the current context/scope given the IL generated for the above. I can see the differences in the IL but I still can't explain the exact cause.
The below is a runnable example that demonstrates the problem.
using System;
using System.Linq;
using System.Reflection;
namespace GetTypeTest
{
public class FindMe{}
class Program
{
static void Main(string[] args)
{
var assemblyName = Assembly.GetExecutingAssembly().FullName;
var className = "GetTypeTest.FindMe";
var classAndAssembly = string.Format("{0}, {1}", className, assemblyName);
// 1) GetType succeeds when input is "class, assembly", using method group
var result = new[] { classAndAssembly }.Select(Type.GetType).ToArray();
Console.WriteLine("1) Method group & class+assembly: {0}", result.First());
// 2) GetType fails when input is just the class name, using method group
var result2 = new[] { className }.Select(Type.GetType).ToArray();
Console.WriteLine("2) Method group & class name only: {0}", result2.First());
// 3) Identical to (2) except using lamba expression - this succeeds...
var result3 = new[] { className }.Select(s => Type.GetType(s)).ToArray();
Console.WriteLine("3) Lambda expression & class name only: {0}", result3.First());
// 4) Method group and core type class name
var result4 = new[] { "System.String" }.Select(Type.GetType).ToArray();
Console.WriteLine("4) Method group for System.String: {0}", result4.First());
Console.ReadLine();
}
}
}
I'd like to know why #2 fails but #3 succeeds.
Am not 100% sure, I may be wrong.. I'll propose what I've examined.Version 2 gets compiled into a func delegate like this
new Func<string, Type>(Type.GetType)
Version 3 gets compiled into a compiler generated method in your same class something like this
and to a func
new Func<string, Type>(Program.<Main>b__0)
So, While executing your enumerator Version2 is just a
func
which will be invoked myWhereSelectArrayIterator<TSource, TResult>
private class lives in System.Core.dllWhere as Version3 lives in your assembly.
Coming to the point. If
Type.GetType
is invoked with partial names(without fully qualified name) It doesn't knows which assembly the type resides, It gets the callingassembly
and assumes the type lives there.Hence Version3 lives in your assembly
Type.GetType
figured out your type's assembly and scans the assembly fully returns the correct type.But this is not the case in Version2. You're not actually invoking the
Type.GetType
there. It is being invoked byWhereSelectArrayIterator... class
which is inSystem.Core.dll
. So this assumes your type lives inSystem.Core.dll
andType.GetType
fails to find out your type.Edit: Following snippet proves above statements were correct
We fake a class in our assembly and name it
System.Linq.Expressions.Expression
to see the behavior.Outputs
Hope this helps