locked
Resolving generic types by full name RRS feed

  • Question

  • Hello, I am trying to turn a Type object into a string (with the Silverlight runtime), send it to a web service then turn it back into a Type object on the server (.NET Framework 3.5).

    The sure-fire way to make this happen normally is to just get the type.AssemblyQualifiedName on the client, then use Type.GetType(...) on the server to get the Type object.

    This won't work for me here, because the assembly qualified name includes version and public key token, both of which vary for the same type between the silverlight runtime and full framework. Even core classes have different AQNs:

    System.Linq.Enumerable, System.Core, Version=2.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e = silverlight

    System.Linq.Enumerable, System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 = full framework 3.5

    So what I need to do is use type.FullName instead, which omits the varying information. It's pretty straightforward to get even a generic type's full name with type.ToString():

    System.Func`2[System.String,System.Collections.Generic.IEnumerable`1[System.Char]]

    But the problem is that when I feed that into Type.GetType(...) on the server side, it gives me null back!

    Does anyone know how to resolve a (generic) type by its full name, or why GetType(...) is failing me?
    Monday, August 24, 2009 2:32 PM

All replies

  • The problem is not really related to generics. The System.Func<T1, TResult> is defined in System.Core which means that Type.GetType() cannot find the type when there is no assembly info in the search string. However, partial assembly name will do the trick as it lets you specify that System.Func<> resides in System.Core while still leaving out the version info. Strip the version info (along with Culture and Key) from the Type.AssemblyQualifiedName like this,

    		static void Main(string[] args)
    		{
    			Type t = typeof(Func<string, IEnumerable<char>>);
    			string s = t.AssemblyQualifiedName;
    			s = ConvertToPartialAssemblyName(s);
    			Type t2 = Type.GetType(s, true);
    		}
    
    		static string ConvertToPartialAssemblyName(string fullyQualified)
    		{
    			string source = fullyQualified + ' ';
    			string[] filters = { ", Version", ", Culture", ", PublicKeyToken" };
    			foreach (string filter in filters)
    			{
    				int start = 0;
    				while ((start = source.IndexOf(filter)) > -1)
    				{
    					int end = source.IndexOfAny(new char[] {',',']',' '}, start + 3);
    					source = source.Remove(start, end - start);
    				}
    			}
    			return source;
    		}


    /Calle 
    - Still confused, but on a higher level -
    Monday, August 24, 2009 4:01 PM
  • That's a neat trick, I didn't know you could axe version, public key token, etc.

    But alas, GetType is still giving me a null back.

    After your ConvertToPartialAssemblyName(...) method's processing, its evaluating to basically:

    Type.GetType("System.Linq.Enumerable, System.Core") == null
    Monday, August 24, 2009 4:36 PM
  • Ah, well that's the downside of partial name, GAC assemblies are not loaded automatically. You have two options:

    Set the CopyLocal=True for the System.Core assembly reference (the System.Core.dll must end up in the bin folder).
      - OR -
    Handle the Current domains AssemblyResolve event, such as

    		static void Main(string[] args)
    		{
    			AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
    			Type t = Type.GetType("System.Linq.Enumerable, System.Core", true);
    			AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(CurrentDomain_AssemblyResolve);
    		}
    
    		static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    		{
    			if (args.Name == "System.Core")
    			{
    				string name = typeof(TimeZoneInfo).Assembly.FullName;
    				return Assembly.Load(name);
    			}
    			return null;
    		}
    As the System.Core.dll already exists in the GAC the AssemblyResolve solution seems like the most elegant.

    /Calle
    - Still confused, but on a higher level -
    Monday, August 24, 2009 7:39 PM
  • Thank you, Calle, I learned two things I didn't know today :D
    Tuesday, August 25, 2009 4:42 AM