renamed IContentStore to IPublishedContentStore. Migrating DynamicNode to Umbraco.Core and cleaning up it's supported codebase.

Starting writing a few unit tests for the new DynamicNode codebase. Will of course leave the original DynamicNode stuff in its
current place for backwards compatibility but will deprecate many of the classes which will call the new ones.
This commit is contained in:
Shannon Deminick
2012-08-17 04:27:47 +06:00
parent 9846d6dc4d
commit 5213d6de5c
61 changed files with 8728 additions and 166 deletions

View File

@@ -0,0 +1,181 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web.Compilation;
using System.Runtime.CompilerServices;
using System.Collections;
using System.Linq.Expressions;
namespace Umbraco.Core.Dynamics
{
internal static class ExtensionMethodFinder
{
private static List<MethodInfo> GetAllExtensionMethods(Type thisType, string name, int argumentCount, bool argsContainsThis)
{
//get extension methods from runtime
var candidates = (
from assembly in BuildManager.GetReferencedAssemblies().Cast<Assembly>()
where assembly.IsDefined(typeof(ExtensionAttribute), false)
from type in assembly.GetTypes()
where (type.IsDefined(typeof(ExtensionAttribute), false)
&& type.IsSealed && !type.IsGenericType && !type.IsNested)
from method in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
// this filters extension methods
where method.IsDefined(typeof(ExtensionAttribute), false)
select method
);
//search an explicit type (e.g. Enumerable, where most of the Linq methods are defined)
//if (explicitTypeToSearch != null)
//{
candidates = candidates.Concat(typeof(IEnumerable).GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic));
//}
//filter by name
var methodsByName = candidates.Where(m => m.Name == name);
var isGenericAndRightParamCount = methodsByName.Where(m => m.GetParameters().Length == argumentCount + (argsContainsThis ? 0 : 1));
//find the right overload that can take genericParameterType
//which will be either DynamicNodeList or List<DynamicNode> which is IEnumerable`
var withGenericParameterType = isGenericAndRightParamCount.Select(m => new { m, t = firstParameterType(m) });
var methodsWhereArgZeroIsTargetType = (from method in withGenericParameterType
where
method.t != null && methodArgZeroHasCorrectTargetType(method.m, method.t, thisType)
select method);
return methodsWhereArgZeroIsTargetType.Select(mt => mt.m).ToList();
}
private static bool methodArgZeroHasCorrectTargetType(MethodInfo method, Type firstArgumentType, Type thisType)
{
//This is done with seperate method calls because you can't debug/watch lamdas - if you're trying to figure
//out why the wrong method is returned, it helps to be able to see each boolean result
return
// is it defined on me?
methodArgZeroHasCorrectTargetType_TypeMatchesExactly(method, firstArgumentType, thisType) ||
// or on any of my interfaces?
methodArgZeroHasCorrectTargetType_AnInterfaceMatches(method, firstArgumentType, thisType) ||
// or on any of my base types?
methodArgZeroHasCorrectTargetType_IsASubclassOf(method, firstArgumentType, thisType) ||
//share a common interface (e.g. IEnumerable)
methodArgZeroHasCorrectTargetType_ShareACommonInterface(method, firstArgumentType, thisType);
}
private static bool methodArgZeroHasCorrectTargetType_ShareACommonInterface(MethodInfo method, Type firstArgumentType, Type thisType)
{
Type[] interfaces = firstArgumentType.GetInterfaces();
if (interfaces.Length == 0)
{
return false;
}
bool result = interfaces.All(i => thisType.GetInterfaces().Contains(i));
return result;
}
private static bool methodArgZeroHasCorrectTargetType_IsASubclassOf(MethodInfo method, Type firstArgumentType, Type thisType)
{
bool result = thisType.IsSubclassOf(firstArgumentType);
return result;
}
private static bool methodArgZeroHasCorrectTargetType_AnInterfaceMatches(MethodInfo method, Type firstArgumentType, Type thisType)
{
bool result = thisType.GetInterfaces().Contains(firstArgumentType);
return result;
}
private static bool methodArgZeroHasCorrectTargetType_TypeMatchesExactly(MethodInfo method, Type firstArgumentType, Type thisType)
{
bool result = (thisType == firstArgumentType);
return result;
}
private static Type firstParameterType(MethodInfo m)
{
ParameterInfo[] p = m.GetParameters();
if (p.Count() > 0)
{
return p.First().ParameterType;
}
return null;
}
public static MethodInfo FindExtensionMethod(Type thisType, object[] args, string name, bool argsContainsThis)
{
Type genericType = null;
if (thisType.IsGenericType)
{
genericType = thisType.GetGenericArguments()[0];
}
var methods = GetAllExtensionMethods(thisType, name, args.Length, argsContainsThis);
if (methods.Count == 0)
{
return null;
}
MethodInfo methodToExecute = null;
if (methods.Count > 1)
{
//Given the args, lets get the types and compare the type sequence to try and find the correct overload
var argTypes = args.ToList().ConvertAll(o =>
{
Expression oe = (o as Expression);
if (oe != null)
{
return oe.Type.FullName;
}
return o.GetType().FullName;
});
var methodsWithArgTypes = methods.ConvertAll(method => new { method = method, types = method.GetParameters().ToList().ConvertAll(pi => pi.ParameterType.FullName) });
var firstMatchingOverload = methodsWithArgTypes.FirstOrDefault(m =>
{
return m.types.SequenceEqual(argTypes);
});
if (firstMatchingOverload != null)
{
methodToExecute = firstMatchingOverload.method;
}
}
if (methodToExecute == null)
{
MethodInfo firstMethod = methods.FirstOrDefault();
// NH: this is to ensure that it's always the correct one being chosen when using the LINQ extension methods
if (methods.Count > 1)
{
var firstGenericMethod = methods.FirstOrDefault(x => x.IsGenericMethodDefinition);
if (firstGenericMethod != null)
{
firstMethod = firstGenericMethod;
}
}
if (firstMethod != null)
{
if (firstMethod.IsGenericMethodDefinition)
{
if (genericType != null)
{
methodToExecute = firstMethod.MakeGenericMethod(genericType);
}
}
else
{
methodToExecute = firstMethod;
}
}
}
return methodToExecute;
}
}
}