Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Normally the framework loads the assemblies on-demand. A different approach would be to use a dynamic load pattern or composite pattern. Starting from the framework 4.0, MS introduced the <a href="http://msdn.microsoft.com/en-us/library/bb384200(v=vs.110).aspx" rel="nofollow">System.Addin</a> namespace to help programmers in this. I have the following class which I use in my projects to achieve the same with Framework 2.0 compatibility:</p> <pre><code>using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; namespace MyNamespace { [Serializable] public enum CompositeLoaderFilter { ImplementsInterface = 0, InheritsBaseClass = 1 } [Serializable] public static class Composite { private static readonly CompositeManager manager = new CompositeManager(); public static CompositeManager Manager { get { return manager; } } } [Serializable] public class CompositeManager : MarshalByRefObject { private SortedList&lt;string, Type&gt; m_addIns; public int GetInMemoryComponents(Type addInType, CompositeLoaderFilter filter) { m_addIns = internal_GetInMemoryServices(addInType, filter); return m_addIns.Count; } public int GetComponents(Type addInType, CompositeLoaderFilter filter) { string addInPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); return GetComponents(addInPath, "*.dll", SearchOption.TopDirectoryOnly, addInType, filter); } public int GetComponents(string addInSearchPattern, Type addInType, CompositeLoaderFilter filter) { string addInPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); return GetComponents(addInPath, addInSearchPattern, SearchOption.TopDirectoryOnly, addInType, filter); } public int GetComponents(string addInPath, string addInSearchPattern, Type addInType, CompositeLoaderFilter filter) { return GetComponents(addInPath, addInSearchPattern, SearchOption.TopDirectoryOnly, addInType, filter); } public int GetComponents(string addInPath, string addInSearchPattern, SearchOption addInSearchOption, Type addInType, CompositeLoaderFilter filter) { AppDomainSetup setup = AppDomain.CurrentDomain.SetupInformation; setup.PrivateBinPath = addInPath; setup.ShadowCopyFiles = "false"; AppDomain m_appDomain = AppDomain.CreateDomain("MyNamespace.CompositeManager", null, setup); CompositeManager m_remoteLoader = (CompositeManager)m_appDomain.CreateInstanceFromAndUnwrap(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "MyAssembly.dll"), "MyNamespace.CompositeManager"); m_addIns = m_remoteLoader.RemoteGetServices(addInPath, addInSearchPattern, addInSearchOption, addInType, filter); #if DEBUG DebugLoadedAssemblies(); #endif AppDomain.Unload(m_appDomain); return m_addIns.Count; } public object CreateInstance(string typeName) { if (!m_addIns.ContainsKey(typeName)) throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Type {0} was not loaded..", typeName), "typeName"); MethodInfo method = m_addIns[typeName].GetMethod("GetInstance", BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy); if (method != null) return method.Invoke(m_addIns[typeName], null); else return Activator.CreateInstance(m_addIns[typeName]); } public object CreateInstance(Type type) { if (type == null) throw new ArgumentNullException("type", "Type is null"); if (!m_addIns.ContainsKey(type.FullName)) throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Type {0} was not loaded..", type.FullName), "type"); MethodInfo method = type.GetMethod("GetInstance", BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy); if (method != null) return method.Invoke(type, null); else return Activator.CreateInstance(type); } public T CreateInstance&lt;T&gt;() { if (!m_addIns.ContainsKey(typeof(T).FullName)) throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Type {0} was not loaded..", typeof(T).FullName), "T"); MethodInfo method = typeof(T).GetMethod("GetInstance", BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy); if (method != null) return (T)method.Invoke(typeof(T), null); else return Activator.CreateInstance&lt;T&gt;(); } public IEnumerable&lt;Type&gt; AvailableServices { get { foreach (KeyValuePair&lt;string, Type&gt; item in m_addIns) { yield return item.Value; } } } public Type[] AvailableTypes { get { List&lt;Type&gt; list = new List&lt;Type&gt;(); foreach (KeyValuePair&lt;string, Type&gt; item in m_addIns) list.Add(item.Value); return list.ToArray(); } } public T[] GetObjects&lt;T&gt;() { List&lt;T&gt; list = new List&lt;T&gt;(); foreach (KeyValuePair&lt;string, Type&gt; item in m_addIns) list.Add((T)CreateInstance(item.Value)); return list.ToArray(); } public object[] AvailableObjects { get { List&lt;object&gt; list = new List&lt;object&gt;(); foreach (KeyValuePair&lt;string, Type&gt; item in m_addIns) list.Add(CreateInstance(item.Value)); return list.ToArray(); } } internal SortedList&lt;string, Type&gt; internal_GetInMemoryServices(Type addInType, CompositeLoaderFilter filter) { SortedList&lt;string, Type&gt; validAddIns = new SortedList&lt;string, Type&gt;(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { Type[] types = assembly.GetTypes(); foreach (Type type in types) { switch (filter) { case CompositeLoaderFilter.ImplementsInterface: if (type.GetInterface(addInType.Name) != null) validAddIns.Add(type.FullName, type); break; case CompositeLoaderFilter.InheritsBaseClass: if (type.BaseType == addInType) validAddIns.Add(type.FullName, type); break; } } } catch (FileLoadException flex) { Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "{0} MyNamespace.CompositeManager: {1}", DateTime.Now.ToString(), flex.Message)); } catch (Exception ex) { Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "{0} MyNamespace.CompositeManager: {1}", DateTime.Now.ToString(), ex.Message)); } } return validAddIns; } internal SortedList&lt;string, Type&gt; RemoteGetServices(string addInPath, string addInSearchPattern, SearchOption addInSearchOption, Type addInType, CompositeLoaderFilter filter) { string[] files = Directory.GetFiles(addInPath, addInSearchPattern, addInSearchOption); SortedList&lt;string, Type&gt; validAddIns = new SortedList&lt;string, Type&gt;(); if (files.Length &gt; 0) { foreach (string file in files) { if (String.CompareOrdinal(addInPath, file) != 0) { try { Assembly assembly = Assembly.LoadFrom(file); Type[] types = assembly.GetTypes(); foreach (Type type in types) { switch (filter) { case CompositeLoaderFilter.ImplementsInterface: if (type.GetInterface(addInType.Name) != null) validAddIns.Add(type.FullName, type); break; case CompositeLoaderFilter.InheritsBaseClass: if (type.BaseType == addInType) validAddIns.Add(type.FullName, type); break; } } } catch (FileLoadException flex) { Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "{0} MyNamespace.CompositeManager: {1}", DateTime.Now.ToString(), flex.Message)); } catch (Exception ex) { Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "{0} MyNamespace.CompositeManager: {1}", DateTime.Now.ToString(), ex.Message)); } } } } #if DEBUG DebugLoadedAssemblies(); #endif return validAddIns; } #if DEBUG internal void DebugLoadedAssemblies() { foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies()) { //Debug.WriteLine(string.Format("Domain: {0} Assembly: {1}", AppDomain.CurrentDomain.FriendlyName, a.FullName)); } } #endif } } </code></pre> <p>Following a sample usage:</p> <pre><code>Composite.Manager.GetComponents(typeof(IMyService), CompositeLoaderFilter.ImplementsInterface); IMyService[] services = Composite.Manager.GetObjects&lt;IMyService&gt;(); </code></pre> <p>The class will load all the assemblies in current folder, inspecting them to see if they contains a Type that match the input parameters. Because is impossible to unload an assembly once loaded, the class will load them inside a different AppDomain, which in contrary to single assemblies, can be dropped.</p> <p>In order to use it in your project you should proceed as following:</p> <ul> <li>Remove the (hard) reference to your assembly</li> <li>Implement an interface to communicate with your class</li> <li>Load the types that implements the above interface</li> <li>Use your class through the interface</li> </ul> <p>Hope it helps :)</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload