4 using System.Collections.Generic;
7 using System.Reflection;
8 using System.Runtime.CompilerServices;
9 using SiliconStudio.Core.Diagnostics;
11 namespace SiliconStudio.Core.Reflection
15 private readonly Dictionary<string, Assembly> loadedAssemblies =
new Dictionary<string, Assembly>(StringComparer.InvariantCultureIgnoreCase);
16 private static readonly
string[] KnownAssemblyExtensions = {
".dll",
".exe" };
24 private static List<string> searchDirectoryList;
33 AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
42 if (assemblyFullPath == null)
throw new ArgumentNullException(
"assemblyFullPath");
46 lookupDirectoryList = lookupDirectoryList ??
new List<string>();
47 assemblyFullPath = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, assemblyFullPath));
48 var assemblyDirectory = Path.GetDirectoryName(assemblyFullPath);
50 if (assemblyDirectory == null || !Directory.Exists(assemblyDirectory))
52 throw new ArgumentException(
"Invalid assembly path. Doesn't contain directory information");
55 if (!lookupDirectoryList.Contains(assemblyDirectory, StringComparer.InvariantCultureIgnoreCase))
57 lookupDirectoryList.Add(assemblyDirectory);
60 var previousLookupList = searchDirectoryList;
63 loadingInstance =
this;
64 searchDirectoryList = lookupDirectoryList;
66 return LoadAssemblyFromPathInternal(assemblyFullPath);
70 loadingInstance = null;
71 searchDirectoryList = previousLookupList;
73 if (outputLog != null)
75 log.CopyTo(outputLog);
80 private Assembly LoadAssemblyByName(
string assemblyName)
82 if (assemblyName == null)
throw new ArgumentNullException(
"assemblyName");
84 var assemblyPartialPathList =
new List<string>();
85 assemblyPartialPathList.AddRange(KnownAssemblyExtensions.Select(knownExtension => assemblyName + knownExtension));
87 foreach (var directoryPath
in searchDirectoryList)
89 foreach (var assemblyPartialPath
in assemblyPartialPathList)
91 var assemblyFullPath = Path.Combine(directoryPath, assemblyPartialPath);
92 if (
File.Exists(assemblyFullPath))
94 return LoadAssemblyFromPathInternal(assemblyFullPath);
101 private string CopySafeShadow(
string path)
103 for(
int i = 1; i < 20; i++)
105 var shadowName = Path.ChangeExtension(path,
"shadow" + i);
108 File.Copy(path, shadowName,
true);
119 private Assembly LoadAssemblyFromPathInternal(
string assemblyFullPath)
121 if (assemblyFullPath == null)
throw new ArgumentNullException(
"assemblyFullPath");
123 string safeShadowPath = null;
126 assemblyFullPath = Path.GetFullPath(assemblyFullPath);
128 lock (loadedAssemblies)
131 if (loadedAssemblies.TryGetValue(assemblyFullPath, out assembly))
136 if (!
File.Exists(assemblyFullPath))
140 safeShadowPath = CopySafeShadow(assemblyFullPath);
141 if (safeShadowPath == null)
143 log.Error(
"Cannot create a shadow copy for assembly [{0}]", assemblyFullPath);
149 assembly = Assembly.LoadFile(safeShadowPath);
150 loadedAssemblies.Add(assemblyFullPath, assembly);
154 Assembly.Load(assembly.FullName);
157 foreach (var assemblyRef
in assembly.GetReferencedAssemblies())
159 Assembly.Load(assemblyRef);
163 if (assembly.GetTypes().Length > 0)
165 foreach (var module
in assembly.Modules)
167 RuntimeHelpers.RunModuleConstructor(module.ModuleHandle);
175 log.Error(
"Error while loading assembly reference [{0}]", exception, safeShadowPath ?? assemblyFullPath);
176 var loaderException = exception as ReflectionTypeLoadException;
177 if (loaderException != null)
179 foreach (var exceptionForType
in loaderException.LoaderExceptions)
181 log.Error(
"Unable to load type. See exception.", exceptionForType);
188 static Assembly CurrentDomain_AssemblyResolve(
object sender, ResolveEventArgs args)
191 var container = loadingInstance;
192 if (container != null)
194 var assemblyName =
new AssemblyName(args.Name);
195 return container.LoadAssemblyByName(assemblyName.Name);
SiliconStudio.Core.Diagnostics.LoggerResult LoggerResult
A logger that stores messages locally useful for internal log scenarios.
Assembly LoadAssemblyFromPath(string assemblyFullPath, ILogger outputLog=null, List< string > lookupDirectoryList=null)
Use the default mode depending on the type of the field/property.