diff --git a/src/Umbraco.Core/Dynamics/DynamicDocument.cs b/src/Umbraco.Core/Dynamics/DynamicDocument.cs
index 9a07d5715c..50a474be6c 100644
--- a/src/Umbraco.Core/Dynamics/DynamicDocument.cs
+++ b/src/Umbraco.Core/Dynamics/DynamicDocument.cs
@@ -252,6 +252,8 @@ namespace Umbraco.Core.Dynamics
///
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
+ //TODO: We MUST cache the result here, it is very expensive to keep finding extension methods!
+
try
{
//Property?
@@ -294,6 +296,8 @@ namespace Umbraco.Core.Dynamics
catch
{
+ //TODO: LOg this!
+
result = null;
return false;
}
@@ -316,7 +320,6 @@ namespace Umbraco.Core.Dynamics
var methodTypesToFind = new[]
{
- typeof(IDocument),
typeof(DynamicDocument)
};
diff --git a/src/Umbraco.Core/Dynamics/DynamicDocumentList.cs b/src/Umbraco.Core/Dynamics/DynamicDocumentList.cs
index 8b37f007fe..54bd02689a 100644
--- a/src/Umbraco.Core/Dynamics/DynamicDocumentList.cs
+++ b/src/Umbraco.Core/Dynamics/DynamicDocumentList.cs
@@ -53,6 +53,9 @@ namespace Umbraco.Core.Dynamics
}
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
+
+ //TODO: We MUST cache the result here, it is very expensive to keep finding extension methods and processing this stuff!
+
var name = binder.Name;
if (name == "Where")
{
@@ -353,7 +356,6 @@ namespace Umbraco.Core.Dynamics
var methodTypesToFind = new[]
{
- typeof(IEnumerable),
typeof(IEnumerable),
typeof(DynamicDocumentList)
};
diff --git a/src/Umbraco.Core/Dynamics/ExtensionMethodFinder.cs b/src/Umbraco.Core/Dynamics/ExtensionMethodFinder.cs
index 1939ace694..fdfa8e35f7 100644
--- a/src/Umbraco.Core/Dynamics/ExtensionMethodFinder.cs
+++ b/src/Umbraco.Core/Dynamics/ExtensionMethodFinder.cs
@@ -13,15 +13,21 @@ namespace Umbraco.Core.Dynamics
{
-
- private static List GetAllExtensionMethods(Type thisType, string name, int argumentCount, bool argsContainsThis)
+ ///
+ /// Returns all extension methods found matching the definition
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /// NOTE: This will be an intensive method to call!! Results should be cached!
+ ///
+ private static IEnumerable GetAllExtensionMethods(Type thisType, string name, int argumentCount, bool argsContainsThis)
{
//only scan assemblies we know to contain extension methods (user assemblies)
- //var assembliesToScan = TypeFinder.GetAssembliesWithKnownExclusions();
- var assembliesToScan = new List()
- {
- Assembly.Load("Umbraco.Tests")
- };
+ var assembliesToScan = TypeFinder.GetAssembliesWithKnownExclusions();
//get extension methods from runtime
var candidates = (
@@ -36,11 +42,8 @@ namespace Umbraco.Core.Dynamics
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));
- //}
+ //add the extension methods defined in IEnumerable
+ candidates = candidates.Concat(typeof(IEnumerable).GetMethods(BindingFlags.Static | BindingFlags.Public));
//filter by name
var methodsByName = candidates.Where(m => m.Name == name);
@@ -57,7 +60,7 @@ namespace Umbraco.Core.Dynamics
method.t != null && MethodArgZeroHasCorrectTargetType(method.m, method.t, thisType)
select method);
- return methodsWhereArgZeroIsTargetType.Select(mt => mt.m).ToList();
+ return methodsWhereArgZeroIsTargetType.Select(mt => mt.m);
}
private static bool MethodArgZeroHasCorrectTargetType(MethodInfo method, Type firstArgumentType, Type thisType)
{
@@ -127,30 +130,28 @@ namespace Umbraco.Core.Dynamics
genericType = thisType.GetGenericArguments()[0];
}
- var methods = GetAllExtensionMethods(thisType, name, args.Length, argsContainsThis);
+ var methods = GetAllExtensionMethods(thisType, name, args.Length, argsContainsThis)
+ .ToArray();
- if (methods.Count == 0)
+ if (!methods.Any())
{
return null;
}
MethodInfo methodToExecute = null;
- if (methods.Count > 1)
+ 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);
+ var 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);
- });
+ var methodsWithArgTypes = methods.Select(method => new {method, types = method.GetParameters().Select(pi => pi.ParameterType.FullName) });
+ var firstMatchingOverload = methodsWithArgTypes.FirstOrDefault(m => m.types.SequenceEqual(argTypes));
if (firstMatchingOverload != null)
{
methodToExecute = firstMatchingOverload.method;
@@ -159,9 +160,9 @@ namespace Umbraco.Core.Dynamics
if (methodToExecute == null)
{
- MethodInfo firstMethod = methods.FirstOrDefault();
+ var 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)
+ if (methods.Count() > 1)
{
var firstGenericMethod = methods.FirstOrDefault(x => x.IsGenericMethodDefinition);
if (firstGenericMethod != null)
diff --git a/src/Umbraco.Tests/DynamicDocumentTests.cs b/src/Umbraco.Tests/DynamicDocumentTests.cs
index c7b30229a6..120e8cd992 100644
--- a/src/Umbraco.Tests/DynamicDocumentTests.cs
+++ b/src/Umbraco.Tests/DynamicDocumentTests.cs
@@ -6,6 +6,7 @@ using System.Web;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Dynamics;
+using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web;
@@ -54,7 +55,21 @@ namespace Umbraco.Tests
}
[Test]
- public void Run_Custom_Extension_Method()
+ public void Custom_Extension_Methods()
+ {
+ var dynamicNode = GetDynamicNode(1173);
+ var asDynamic = dynamicNode.AsDynamic();
+
+ Assert.AreEqual("Hello world", asDynamic.DynamicDocumentNoParameters());
+ Assert.AreEqual("Hello world!", asDynamic.DynamicDocumentCustomString("Hello world!"));
+ Assert.AreEqual("Hello world!" + 123 + false, asDynamic.DynamicDocumentMultiParam("Hello world!", 123, false));
+ Assert.AreEqual("Hello world!" + 123 + false, asDynamic.Children.DynamicDocumentListMultiParam("Hello world!", 123, false));
+ Assert.AreEqual("Hello world!" + 123 + false, asDynamic.Children.DynamicDocumentEnumerableMultiParam("Hello world!", 123, false));
+ }
+
+
+ [Test]
+ public void Custom_Extension_Method_With_Params()
{
var dynamicNode = GetDynamicNode(1173);
var asDynamic = dynamicNode.AsDynamic();
@@ -321,10 +336,30 @@ namespace Umbraco.Tests
public static class DynamicDocumentCustomExtensionMethods
{
- public static string ReturnHelloWorld(this DynamicDocument doc)
+ public static string DynamicDocumentNoParameters(this DynamicDocument doc)
{
return "Hello world";
}
+
+ public static string DynamicDocumentCustomString(this DynamicDocument doc, string custom)
+ {
+ return custom;
+ }
+
+ public static string DynamicDocumentMultiParam(this DynamicDocument doc, string custom, int i, bool b)
+ {
+ return custom + i + b;
+ }
+
+ public static string DynamicDocumentListMultiParam(this DynamicDocumentList doc, string custom, int i, bool b)
+ {
+ return custom + i + b;
+ }
+
+ public static string DynamicDocumentEnumerableMultiParam(this IEnumerable doc, string custom, int i, bool b)
+ {
+ return custom + i + b;
+ }
}
}
\ No newline at end of file