diff --git a/build/NuSpecs/UmbracoCms.Core.nuspec b/build/NuSpecs/UmbracoCms.Core.nuspec
index c680dce419..feb530ce99 100644
--- a/build/NuSpecs/UmbracoCms.Core.nuspec
+++ b/build/NuSpecs/UmbracoCms.Core.nuspec
@@ -28,7 +28,7 @@
-
+
diff --git a/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs b/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs
index 94394abb3e..59f149ef09 100644
--- a/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs
+++ b/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs
@@ -174,6 +174,13 @@ namespace Umbraco.Core.Dynamics
if (toExecute != null)
{
var genericArgs = (new[] { (object)thisObject }).Concat(args);
+
+ // else we'd get an exception w/ message "Late bound operations cannot
+ // be performed on types or methods for which ContainsGenericParameters is true."
+ // because MakeGenericMethod must be used to obtain an actual method that can run
+ if (toExecute.ContainsGenericParameters)
+ throw new InvalidOperationException("Method contains generic parameters, something's wrong.");
+
result = toExecute.Invoke(null, genericArgs.ToArray());
}
else
diff --git a/src/Umbraco.Core/Dynamics/ExtensionMethodFinder.cs b/src/Umbraco.Core/Dynamics/ExtensionMethodFinder.cs
index fbfa933e83..0fe21da013 100644
--- a/src/Umbraco.Core/Dynamics/ExtensionMethodFinder.cs
+++ b/src/Umbraco.Core/Dynamics/ExtensionMethodFinder.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Linq.Expressions;
+using System.Web.Services.Description;
using Umbraco.Core.Cache;
namespace Umbraco.Core.Dynamics
@@ -77,87 +78,31 @@ namespace Umbraco.Core.Dynamics
{
var candidates = GetAllExtensionMethodsInAppDomain(runtimeCache);
+ // filter by name
+ var filtr1 = candidates.Where(m => m.Name == name);
- //filter by name
- var methodsByName = candidates.Where(m => m.Name == name);
+ // filter by args count
+ // ensure we add + 1 to the arg count because the 'this' arg is not included in the count above!
+ var filtr2 = filtr1.Where(m => m.GetParameters().Length == argumentCount + 1);
- //ensure we add + 1 to the arg count because the 'this' arg is not included in the count above!
- var isGenericAndRightParamCount = methodsByName.Where(m => m.GetParameters().Length == argumentCount + 1);
+ // filter by first parameter type (target of the extension method)
+ // ie find the right overload that can take genericParameterType
+ // (which will be either DynamicNodeList or List which is IEnumerable)
+ var filtr3 = filtr2.Select(x =>
+ {
+ var t = x.GetParameters()[0].ParameterType; // exists because of +1 above
+ var bindings = new Dictionary>();
+ if (thisType.MatchType(t, bindings) == false) return null;
- //find the right overload that can take genericParameterType
- //which will be either DynamicNodeList or List which is IEnumerable`
+ // create the generic method if necessary
+ if (x.ContainsGenericParameters == false) return x;
+ var targs = t.GetGenericArguments().Select(y => bindings[y.Name].First()).ToArray();
+ return x.MakeGenericMethod(targs);
+ }).Where(x => x != null);
- 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).ToArray();
+ return filtr3.ToArray();
});
- }
-
- 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?
- MethodArgZeroHasCorrectTargetTypeTypeMatchesExactly(method, firstArgumentType, thisType) ||
-
- // or on any of my interfaces?
- MethodArgZeroHasCorrectTargetTypeAnInterfaceMatches(method, firstArgumentType, thisType) ||
-
- // or on any of my base types?
- MethodArgZeroHasCorrectTargetTypeIsASubclassOf(method, firstArgumentType, thisType) ||
-
- //share a common interface (e.g. IEnumerable)
- MethodArgZeroHasCorrectTargetTypeShareACommonInterface(method, firstArgumentType, thisType);
-
-
- }
-
- private static bool MethodArgZeroHasCorrectTargetTypeShareACommonInterface(MethodInfo method, Type firstArgumentType, Type thisType)
- {
- var interfaces = firstArgumentType.GetInterfaces();
- if (interfaces.Length == 0)
- {
- return false;
- }
- var result = interfaces.All(i => thisType.GetInterfaces().Contains(i));
- return result;
- }
-
- private static bool MethodArgZeroHasCorrectTargetTypeIsASubclassOf(MethodInfo method, Type firstArgumentType, Type thisType)
- {
- var result = thisType.IsSubclassOf(firstArgumentType);
- return result;
- }
-
- private static bool MethodArgZeroHasCorrectTargetTypeAnInterfaceMatches(MethodInfo method, Type firstArgumentType, Type thisType)
- {
- var result = thisType.GetInterfaces().Contains(firstArgumentType);
- return result;
- }
-
- private static bool MethodArgZeroHasCorrectTargetTypeTypeMatchesExactly(MethodInfo method, Type firstArgumentType, Type thisType)
- {
- var result = (thisType == firstArgumentType);
- return result;
- }
-
- private static Type FirstParameterType(MethodInfo m)
- {
- var p = m.GetParameters();
- if (p.Any())
- {
- return p.First().ParameterType;
- }
- return null;
}
private static MethodInfo DetermineMethodFromParams(IEnumerable methods, Type genericType, IEnumerable