|
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Collections.ObjectModel;
namespace UndisposedViewer
{
class FinalizerTypeFinder
{
Dictionary<string, IEnumerable<Type>> assemblyTypesCache = new Dictionary<string, IEnumerable<Type>>();
Dictionary<string, object> analyzedAssemblies = new Dictionary<string, object>();
bool recursiveSearch;
string basePath = "";
public IEnumerable<Type> Find(string assemblyPath, bool recursiveSearch)
{
analyzedAssemblies.Clear();
exceptionsDuringFind.Clear();
basePath = System.IO.Path.GetDirectoryName(assemblyPath);
var assembly = Assembly.LoadFrom(assemblyPath);
var assemblyName = assembly.GetName();
this.recursiveSearch = recursiveSearch;
var finalizableTypes = FindFinalizableTypes(assemblyName);
List<Type> cache = new List<Type>();
foreach (Type type in finalizableTypes)
{
cache.Add(type);
yield return type;
}
AddToCache(assemblyName.FullName, cache);
if (exceptionsDuringFind.Count > 0)
{
throw new Exception("Could not find all finalizable types. " + Environment.NewLine +
string.Join(Environment.NewLine, exceptionsDuringFind.ConvertAll(ex => ex.ToString()).ToArray()));
}
}
List<Exception> exceptionsDuringFind = new List<Exception>();
private IEnumerable<Type> FindFinalizableTypes(AssemblyName assemblyName)
{
IEnumerable<Type> types;
if (IsPresentInCache(assemblyName.FullName, out types))
{
foreach (Type t in types)
yield return t;
}
else
{
Assembly assembly = null;
try
{
assembly = Assembly.Load(assemblyName);
}
catch (Exception)
{
try
{
assembly = Assembly.LoadFrom(
System.IO.Path.Combine(basePath, assemblyName.Name + ".dll"));
}
catch (Exception e)
{
exceptionsDuringFind.Add(e);
}
}
if (assembly != null)
{
foreach (Type t in assembly.GetTypes())
{
if (HasFinalizer(t))
yield return t;
}
if (recursiveSearch)
{
foreach (AssemblyName a in assembly.GetReferencedAssemblies())
{
if (!IsAlreadyAnalyzed(a.FullName))
{
analyzedAssemblies.Add(a.FullName, null);
IEnumerable<Type> finalizableTypes = FindFinalizableTypes(a);
foreach (Type t in finalizableTypes)
yield return t;
AddToCache(a.FullName, new List<Type>(finalizableTypes));
}
}
}
}
}
}
private bool IsAlreadyAnalyzed(string assemblyName)
{
return analyzedAssemblies.ContainsKey(assemblyName);
}
private void AddToCache(string assemblyName, IEnumerable<Type> types)
{
if (!assemblyTypesCache.ContainsKey(assemblyName))
assemblyTypesCache.Add(assemblyName, types);
}
private bool IsPresentInCache(string assemblyName, out IEnumerable<Type> types)
{
return assemblyTypesCache.TryGetValue(assemblyName, out types);
}
private bool HasFinalizer(Type type)
{
const string finalizerMethodName = "Finalize";
return type.GetMethod(finalizerMethodName, BindingFlags.NonPublic | BindingFlags.DeclaredOnly | BindingFlags.Instance) != null;
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
I'm a 27 yrs old developer working with Atmel R&D India Pvt. Ltd., Chennai. I'm currently working in C# and C++, but I've done some Java programming as well. I was a Microsoft MVP in Visual C# from 2007 to 2009.
You can read
My Blog here. I've also done some open source software - please visit my
website to know more.