Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Metadata / DefaultAssemblyResolver.cs
1 //---------------------------------------------------------------------
2 // <copyright file="DefaultAssemblyResolver.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner       Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9
10 using System.Reflection;
11 using System.IO;
12 using System.Diagnostics;
13 using System.Collections.Generic;
14 using System.Linq;
15 using System.Collections;
16
17 namespace System.Data.Metadata.Edm
18 {
19     internal class DefaultAssemblyResolver : MetadataArtifactAssemblyResolver
20     {
21         internal override bool TryResolveAssemblyReference(AssemblyName refernceName, out Assembly assembly)
22         {
23             assembly = ResolveAssembly(refernceName);
24             return assembly != null;
25         }
26
27
28         internal override IEnumerable<Assembly> GetWildcardAssemblies()
29         {
30             return GetAllDiscoverableAssemblies();
31         }
32
33         internal Assembly ResolveAssembly(AssemblyName referenceName)
34         {
35             Assembly assembly = null;
36
37             // look in the already loaded assemblies
38             foreach (Assembly current in GetAlreadyLoadedNonSystemAssemblies())
39             {
40                 if (AssemblyName.ReferenceMatchesDefinition(referenceName, new AssemblyName(current.FullName)))
41                 {
42                     return current;
43                 }
44             }
45
46             // try to load this one specifically
47             if (assembly == null)
48             {
49                 assembly = MetadataAssemblyHelper.SafeLoadReferencedAssembly(referenceName);
50                 if (assembly != null)
51                 {
52                     return assembly;
53                 }
54             }
55
56             // try all the discoverable ones
57             TryFindWildcardAssemblyMatch(referenceName, out assembly);
58
59             return assembly;
60         }
61
62         private bool TryFindWildcardAssemblyMatch(AssemblyName referenceName, out Assembly assembly)
63         {
64             Debug.Assert(referenceName != null);
65
66             foreach (Assembly current in GetAllDiscoverableAssemblies())
67             {
68                 if (AssemblyName.ReferenceMatchesDefinition(referenceName, new AssemblyName(current.FullName)))
69                 {
70                     assembly = current;
71                     return true;
72                 }
73             }
74
75             assembly = null;
76             return false;
77         }
78
79
80         /// <summary>
81         /// Return all assemblies loaded in the current AppDomain that are not signed
82         /// with the Microsoft Key.
83         /// </summary>
84         /// <returns>A list of assemblies</returns>
85         private static IEnumerable<Assembly> GetAlreadyLoadedNonSystemAssemblies()
86         {
87             Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
88             return assemblies.Where(a => a != null && !MetadataAssemblyHelper.ShouldFilterAssembly(a));
89         }
90
91         /// <summary>
92         /// This method returns a list of assemblies whose contents depend on whether we
93         /// are running in an ASP.NET environment. If we are indeed in a Web/ASP.NET
94         /// scenario, we pick up the assemblies that all page compilations need to
95         /// reference. If not, then we simply get the list of assemblies referenced by
96         /// the entry assembly.
97         /// </summary>
98         /// <returns>A list of assemblies</returns>
99         private static IEnumerable<Assembly> GetAllDiscoverableAssemblies()
100         {
101             Assembly assembly = Assembly.GetEntryAssembly();
102             HashSet<Assembly> assemblyList = new HashSet<Assembly>(
103                 AssemblyComparer.Instance);
104
105             foreach (Assembly loadedAssembly in GetAlreadyLoadedNonSystemAssemblies())
106             {
107                 assemblyList.Add(loadedAssembly);
108             }
109
110             AspProxy aspProxy = new AspProxy();
111             if (!aspProxy.IsAspNetEnvironment())
112             {
113                 if (assembly == null)
114                 {
115                     return assemblyList;
116                 }
117
118                 assemblyList.Add(assembly);
119
120                 foreach (Assembly referenceAssembly in MetadataAssemblyHelper.GetNonSystemReferencedAssemblies(assembly))
121                 {
122                     assemblyList.Add(referenceAssembly);
123                 }
124
125                 return assemblyList;
126             }
127
128             if (aspProxy.HasBuildManagerType())
129             {
130                 IEnumerable<Assembly> referencedAssemblies = aspProxy.GetBuildManagerReferencedAssemblies();
131                 // filter out system assemblies
132                 if (referencedAssemblies != null)
133                 {
134                     foreach (Assembly referencedAssembly in referencedAssemblies)
135                     {
136                         if (MetadataAssemblyHelper.ShouldFilterAssembly(referencedAssembly))
137                         {
138                             continue;
139                         }
140
141                         assemblyList.Add(referencedAssembly);
142                     }
143                 }
144             }
145
146             return assemblyList.Where(a => a != null);
147         }
148
149         internal sealed class AssemblyComparer : IEqualityComparer<Assembly>
150         {
151             // use singleton
152             private AssemblyComparer() { }
153
154             private static AssemblyComparer _instance = new AssemblyComparer();
155             public static AssemblyComparer Instance{ get { return _instance; } }
156
157             /// <summary>
158             /// if two assemblies have the same full name, we will consider them as the same.
159             /// for example,
160             /// both of x and y have the full name as "{RES, Version=3.5.0.0, Culture=neutral, PublicKeyToken=null}",
161             /// although they are different instances since the ReflectionOnly field in them are different, we sitll 
162             /// consider them as the same.
163             /// </summary>
164             /// <param name="x"></param>
165             /// <param name="y"></param>
166             /// <returns></returns>
167             public bool Equals(Assembly x, Assembly y)
168             {
169                 AssemblyName xname = new AssemblyName(x.FullName);
170                 AssemblyName yname = new AssemblyName(y.FullName);
171                 // return *true* when either the reference are the same 
172                 // *or* the Assembly names are commutative equal
173                 return object.ReferenceEquals(x, y)
174                     || (AssemblyName.ReferenceMatchesDefinition(xname, yname)
175                          && AssemblyName.ReferenceMatchesDefinition(yname, xname));
176             }
177
178             public int GetHashCode(Assembly assembly)
179             {
180                 return assembly.FullName.GetHashCode();
181             }
182         }
183     }
184 }