Assembly Search Type

I had a problem returning the Type.GetType(myTypeName) null code because an assembly with this type is not the current executing assembly.

The solution I found for this problem is the following:

 var assemblies = AppDomain.CurrentDomain.GetAssemblies(); Type myType = assemblies.SelectMany(a => a.GetTypes()) .Single(t => t.FullName == myTypeName); 

The problem is that the first run of this code throws a "Sequence contains no matching element" exception. When I call this part of the code again, everything is in order and the type is loaded.

Can someone explain this behavior? Why is the assembly / type not required in the first call area?

+4
source share
5 answers

The problem you are facing is caused by the construction of the GetAssemblies method of the AppDomain class - as per the documentation of this method:

Gets the assemblies that have been loaded into the execution context of this application domain.

So, when you cannot find the first time in your program type, its assembly is clearly not loaded by the application. And then - when some functions from the assembly were used containing the type in question, the assembly is already loaded, and the same code can already find the missing type.

Please try downloading assemblies directly. Instead of using:

 var assemblies = AppDomain.CurrentDomain.GetAssemblies(); 

you can use:

 List<Assembly> assemblies = Assembly.GetEntryAssembly().GetReferencedAssemblies().Select(assembly => Assembly.LoadFrom(assembly.Name)).ToList(); 
+2
source

It is possible that the type is in an assembly that is not yet loaded. This is later on in your program. If you look at the output window, this will give you an idea of ​​when the assemblies load.

+2
source

Another answer shows a better way to get (at runtime) a Type defined in Assembly that cannot be loaded:

 var T1 = Type.GetType("System.Web.Configuration.IAssemblyCache, " + "System.Web, " + "Version=4.0.0.0, " + "Culture=neutral, " + "PublicKeyToken=b03f5f7f11d50a3a"); 

As you can see, unfortunately, this method requires that you provide the full AssemblyQualifiedName Type and will not work with any of the shortened forms of the assembly name I tried. This somewhat strikes our main goals. If you knew what the assembly details, it would be much harder to just download it yourself:

 var T2 = Assembly.Load("System.Web, " + "Version=4.0.0.0, " + "Culture=neutral, " + "PublicKeyToken=b03f5f7f11d50a3a") .GetType("System.Web.Configuration.IAssemblyCache"); 

Although these two examples look the same, they execute very different code codes; note, for example, that the latest version causes an instance to overload on Assembly.GetType compared to a static call to Type.GetType . Because of this, the second version is probably faster or more efficient. In any case, it seems that you get into the next internal CLR method and with the second argument set to false , and therefore none of the methods try to find the required assembly on your behalf.

[System.Runtime.Remoting.RemotingServices]
private static RuntimeType LoadClrTypeWithPartialBindFallback (
String typeName,
bool partialFallback);

A small step forward from these inconveniences will be to instead invoke this CLR method yourself, but with the partialFallback parameter set to true . In this mode, the function will take a shortened version of AssemblyQualifiedName and find and load the appropriate assembly, if necessary:

 static Func<String, bool, TypeInfo> LoadClrTypeWithPartialBindFallback = typeof(RemotingServices) .GetMethod("LoadClrTypeWithPartialBindFallback", (BindingFlags)0x28) .CreateDelegate(typeof(Func<String, bool, TypeInfo>)) as Func<String, bool, TypeInfo>; // ... var T3 = LoadClrTypeWithPartialBindFallback( "System.Web.Configuration.IAssemblyCache, System.Web", true); // <-- enables searching for the assembly 

This works as shown, and also continues to support the full description of AssemblyQualifiedName , as in the previous examples. This is a small improvement, but it is still not a completely unqualified namespace search, since you still need to specify the assembly short name, even if it can be inferred from the namespace that appears in the type name itself.

+1
source

And if you exlucde the mscorlib assembly ??, you can try the following:

  var assemblies = AppDomain.CurrentDomain.GetAssemblies().Where(asb=>!asb.FullName.StartsWith("mscorlib")).ToList(); Type myType = assemblies.SelectMany(a => a.GetTypes()) .Single(t => t.FullName == myTypeName); 
0
source

By the way, if you know the FullName assembly containing the type (or the assembly containing the TypeForwardedToAttribute for the type), you can use Type.GetType . In particular, Type.GetType(Assembly.CreateQualifiedName(assembly.FullName, myTypeName)) , which will look something like this:

 Type.GetType("Some.Complete.Namespace.myTypeName, Some.Assembly.Name, Version=1.2.3.4, Culture=neutral, PublicKeyToken=ffffffffffffffff"); 

This will load the assembly if it has not yet been accepted, if the infrastructure can resolve the location of the assembly.

Here is my LinqPad request example confirming the TypeForwardedToAttribute bracket:

 var u = (from a in AppDomain.CurrentDomain.GetAssemblies() let t = a.GetType("System.Lazy`2") where t != null select t).FirstOrDefault(); (u?.AssemblyQualifiedName).Dump(); u = Type.GetType("System.Lazy`2, System.Runtime, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"); (u?.AssemblyQualifiedName).Dump(); 

Output:

zero
System.Lazy`2, System.ComponentModel.Composition, Version = 4.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089

0
source

Source: https://habr.com/ru/post/1434165/


All Articles