diff --git a/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs b/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs
new file mode 100644
index 0000000000..a7bb20ef5b
--- /dev/null
+++ b/src/Umbraco.Core/Dynamics/DynamicInstanceHelper.cs
@@ -0,0 +1,178 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Dynamic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using Umbraco.Core.Logging;
+
+namespace Umbraco.Core.Dynamics
+{
+ ///
+ /// A helper class to try invoke members, find properties, etc...
+ ///
+ internal class DynamicInstanceHelper
+ {
+
+ internal class TryInvokeMemberResult
+ {
+ public object ObjectResult { get; private set; }
+ public TryInvokeMemberSuccessReason Reason { get; private set; }
+
+ public TryInvokeMemberResult(object result, TryInvokeMemberSuccessReason reason)
+ {
+ ObjectResult = result;
+ Reason = reason;
+ }
+ }
+
+ internal enum TryInvokeMemberSuccessReason
+ {
+ FoundProperty,
+ FoundMethod,
+ FoundExtensionMethod
+ }
+
+ ///
+ /// Attempts to invoke a member based on the dynamic instance
+ ///
+ ///
+ /// The object instance to invoke the extension method for
+ ///
+ ///
+ ///
+ ///
+ /// First tries to find a property with the binder name, if that fails it will try to find a static or instance method
+ /// on the object that matches the binder name
+ ///
+ public static Attempt TryInvokeMember(T thisObject, InvokeMemberBinder binder, object[] args)
+ {
+ return TryInvokeMember(thisObject, binder, args, null);
+ }
+
+ ///
+ /// Attempts to invoke a member based on the dynamic instance
+ ///
+ ///
+ /// The object instance to invoke the extension method for
+ ///
+ ///
+ /// The types to scan for extension methods
+ ///
+ ///
+ /// First tries to find a property with the binder name, if that fails it will try to find a static or instance method
+ /// on the object that matches the binder name, if that fails it will then attempt to invoke an extension method
+ /// based on the binder name and the extension method types to scan.
+ ///
+ public static Attempt TryInvokeMember(T thisObject,
+ InvokeMemberBinder binder,
+ object[] args,
+ IEnumerable findExtensionMethodsOnTypes)
+ {
+ //TODO: We MUST cache the result here, it is very expensive to keep finding extension methods!
+ object result;
+ try
+ {
+ //Property?
+ result = typeof(T).InvokeMember(binder.Name,
+ System.Reflection.BindingFlags.Instance |
+ System.Reflection.BindingFlags.Public |
+ System.Reflection.BindingFlags.GetProperty,
+ null,
+ thisObject,
+ args);
+ return new Attempt(true, new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundProperty));
+ }
+ catch (MissingMethodException)
+ {
+ try
+ {
+ //Static or Instance Method?
+ result = typeof(T).InvokeMember(binder.Name,
+ System.Reflection.BindingFlags.Instance |
+ System.Reflection.BindingFlags.Public |
+ System.Reflection.BindingFlags.Static |
+ System.Reflection.BindingFlags.InvokeMethod,
+ null,
+ thisObject,
+ args);
+ return new Attempt(true, new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundMethod));
+ }
+ catch (MissingMethodException)
+ {
+ if (findExtensionMethodsOnTypes != null)
+ {
+ try
+ {
+ result = FindAndExecuteExtensionMethod(thisObject, args, binder.Name, findExtensionMethodsOnTypes);
+ return new Attempt(true, new TryInvokeMemberResult(result, TryInvokeMemberSuccessReason.FoundExtensionMethod));
+ }
+ catch (TargetInvocationException ext)
+ {
+ //don't log here, we return this exception because the caller may need to do something specific when
+ //this exception occurs.
+ return new Attempt(ext);
+ }
+ catch (Exception ex)
+ {
+ var sb = new StringBuilder("An error occurred finding an executing an extension method for type ");
+ sb.Append(typeof (T));
+ sb.Append("Types searched for extension methods were ");
+ foreach(var t in findExtensionMethodsOnTypes)
+ {
+ sb.Append(t + ",");
+ }
+ LogHelper.Error(sb.ToString(), ex);
+ return new Attempt(ex);
+ }
+ }
+ return Attempt.False;
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.Error("An unhandled exception occurred in method TryInvokeMember", ex);
+ return new Attempt(ex);
+ }
+ }
+
+ ///
+ /// Attempts to find an extension method that matches the name and arguments based on scanning the Type's passed in
+ /// to the findMethodsOnTypes parameter
+ ///
+ /// The instance object to execute the extension method for
+ ///
+ ///
+ ///
+ ///
+ internal static object FindAndExecuteExtensionMethod(T thisObject,
+ object[] args,
+ string name,
+ IEnumerable findMethodsOnTypes)
+ {
+ object result = null;
+
+ //find known extension methods that match the first type in the list
+ MethodInfo toExecute = null;
+ foreach (var t in findMethodsOnTypes)
+ {
+ toExecute = ExtensionMethodFinder.FindExtensionMethod(t, args, name, false);
+ if (toExecute != null)
+ break;
+ }
+
+ if (toExecute != null)
+ {
+ var genericArgs = (new[] { (object)thisObject }).Concat(args);
+ result = toExecute.Invoke(null, genericArgs.ToArray());
+ }
+ else
+ {
+ throw new MissingMethodException();
+ }
+ return result;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Dynamics/DynamicXml.cs b/src/Umbraco.Core/Dynamics/DynamicXml.cs
index 80a3303a60..ef3114f111 100644
--- a/src/Umbraco.Core/Dynamics/DynamicXml.cs
+++ b/src/Umbraco.Core/Dynamics/DynamicXml.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Dynamic;
+using System.Reflection;
using System.Xml.Linq;
using System.Xml.XPath;
using System.Collections;
@@ -10,7 +11,7 @@ using System.Web;
namespace Umbraco.Core.Dynamics
{
- public class DynamicXml : DynamicObject, IEnumerable
+ public class DynamicXml : DynamicObject, IEnumerable, IEnumerable
{
public XElement BaseElement { get; set; }
@@ -70,7 +71,51 @@ namespace Umbraco.Core.Dynamics
HandleIEnumerableXElement(elements, out result);
return true; //anyway
}
- return base.TryInvokeMember(binder, args, out result);
+
+ //ok, now lets try to match by member, property, extensino method
+ var attempt = DynamicInstanceHelper.TryInvokeMember(this, binder, args, new[]
+ {
+ typeof (IEnumerable),
+ typeof (DynamicXml)
+ });
+
+ if (attempt.Success)
+ {
+ result = attempt.Result.ObjectResult;
+
+ //need to check the return type and possibly cast if result is from an extension method found
+ if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod)
+ {
+ if (attempt.Result.ObjectResult != null)
+ {
+ if (attempt.Result.ObjectResult is XElement)
+ {
+ result = new DynamicXml((XElement) attempt.Result.ObjectResult);
+ }
+ if (attempt.Result.ObjectResult is IEnumerable)
+ {
+ result = ((IEnumerable) attempt.Result.ObjectResult).Select(x => new DynamicXml(x));
+ }
+ if (attempt.Result.ObjectResult is IEnumerable)
+ {
+ result = ((IEnumerable)attempt.Result.ObjectResult).Select(x => new DynamicXml(x.BaseElement));
+ }
+ }
+ }
+ return true;
+ }
+
+ //this is the result of an extension method execution gone wrong so we return dynamic null
+ if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod
+ && attempt.Error != null && attempt.Error is TargetInvocationException)
+ {
+ result = new DynamicNull();
+ return true;
+ }
+
+ result = null;
+ return false;
+
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
@@ -181,20 +226,41 @@ namespace Umbraco.Core.Dynamics
return new DynamicXml(this.BaseElement.XPathSelectElements(expression).FirstOrDefault());
}
- public IEnumerator GetEnumerator()
- {
- return this.BaseElement.Elements().Select(e => new DynamicXml(e)).GetEnumerator();
- }
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return this.BaseElement.Elements().GetEnumerator();
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ return this.BaseElement.Elements().Select(e => new DynamicXml(e)).GetEnumerator();
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
public int Count()
{
- return this.BaseElement.Elements().Count();
+ return ((IEnumerable)this).Count();
}
public bool Any()
{
- return this.BaseElement.Elements().Any();
+ return ((IEnumerable)this).Any();
}
+ public IEnumerable Take(int count)
+ {
+ return ((IEnumerable)this).Take(count);
+ }
+
+ public IEnumerable Skip(int count)
+ {
+ return ((IEnumerable)this).Skip(count);
+ }
+
public bool IsNull()
{
return false;
@@ -514,7 +580,7 @@ namespace Umbraco.Core.Dynamics
}
public IEnumerable Ancestors(Func func)
{
- List ancestorList = new List();
+ var ancestorList = new List();
var node = this.BaseElement;
while (node != null)
{
@@ -661,5 +727,7 @@ namespace Umbraco.Core.Dynamics
}
}
}
+
+
}
}
diff --git a/src/Umbraco.Core/Dynamics/ExtensionMethodFinder.cs b/src/Umbraco.Core/Dynamics/ExtensionMethodFinder.cs
index 6dd8a1ad12..2fe86ddeec 100644
--- a/src/Umbraco.Core/Dynamics/ExtensionMethodFinder.cs
+++ b/src/Umbraco.Core/Dynamics/ExtensionMethodFinder.cs
@@ -44,7 +44,7 @@ namespace Umbraco.Core.Dynamics
);
//add the extension methods defined in IEnumerable
- candidates = candidates.Concat(typeof(IEnumerable).GetMethods(BindingFlags.Static | BindingFlags.Public));
+ candidates = candidates.Concat(typeof(Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public));
//filter by name
var methodsByName = candidates.Where(m => m.Name == name);
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 1415d981ae..36b279ce81 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -65,6 +65,7 @@
+
diff --git a/src/Umbraco.Tests/PublishedContent/DynamicPublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/DynamicPublishedContentTests.cs
index 3e0d52feb1..e8bb815802 100644
--- a/src/Umbraco.Tests/PublishedContent/DynamicPublishedContentTests.cs
+++ b/src/Umbraco.Tests/PublishedContent/DynamicPublishedContentTests.cs
@@ -77,6 +77,7 @@ namespace Umbraco.Tests.PublishedContent
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]
diff --git a/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs b/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs
index 479fcc5929..7c1a3598fb 100644
--- a/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs
+++ b/src/Umbraco.Tests/PublishedContent/DynamicXmlTests.cs
@@ -3,6 +3,7 @@ using System.Diagnostics;
using Microsoft.CSharp.RuntimeBinder;
using NUnit.Framework;
using Umbraco.Core.Dynamics;
+using System.Linq;
namespace Umbraco.Tests.PublishedContent
{
@@ -10,6 +11,65 @@ namespace Umbraco.Tests.PublishedContent
public class DynamicXmlTests
{
+ [Test]
+ public void Custom_Extension_Method_Legacy()
+ {
+ var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg";
+ var typedXml = new global::umbraco.MacroEngines.DynamicXml(xml);
+ dynamic dynamicXml = typedXml;
+
+ //we haven't explicitly defined ElementAt so this will dynamically invoke this method
+ var element = dynamicXml.ElementAt(0);
+
+ Assert.AreEqual("1057", Enumerable.First(element.BaseElement.Elements()).Attribute("id").Value);
+ }
+
+ [Test]
+ public void Custom_Extension_Method()
+ {
+ var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg";
+ var typedXml = new DynamicXml(xml);
+
+ dynamic dynamicXml = typedXml;
+
+ //we haven't explicitly defined ElementAt so this will dynamically invoke this method
+ var element = dynamicXml.ElementAt(0);
+
+ Assert.AreEqual("1057", Enumerable.First(element.BaseElement.Elements()).Attribute("id").Value);
+ }
+
+ [Test]
+ public void Take_Legacy()
+ {
+ var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg";
+ var typedXml = new global::umbraco.MacroEngines.DynamicXml(xml);
+ dynamic dynamicXml = typedXml;
+ var typedTaken = typedXml.Take(1);
+ var dynamicTaken = dynamicXml.Take(1);
+
+ Assert.AreEqual(1, typedTaken.Count());
+ Assert.AreEqual(1, Enumerable.Count(dynamicTaken));
+
+ Assert.AreEqual("1057", typedTaken.ElementAt(0).BaseElement.Elements().First().Attribute("id").Value);
+ Assert.AreEqual("1057", Enumerable.First(Enumerable.ElementAt(dynamicTaken, 0).BaseElement.Elements()).Attribute("id").Value);
+ }
+
+ [Test]
+ public void Take()
+ {
+ var xml = "/media/54/tulips.jpg1024768620888jpg/media/41/hydrangeas.jpg1024768595284jpg";
+ var typedXml = new DynamicXml(xml);
+ dynamic dynamicXml = typedXml;
+ var typedTaken = typedXml.Take(1);
+ var dynamicTaken = dynamicXml.Take(1);
+
+ Assert.AreEqual(1, typedTaken.Count());
+ Assert.AreEqual(1, Enumerable.Count(dynamicTaken));
+
+ Assert.AreEqual("1057", typedTaken.ElementAt(0).BaseElement.Elements().First().Attribute("id").Value);
+ Assert.AreEqual("1057", Enumerable.First(Enumerable.ElementAt(dynamicTaken, 0).BaseElement.Elements()).Attribute("id").Value);
+ }
+
[Test]
public void Ensure_Legacy_Objects_Are_Returned()
{
diff --git a/src/Umbraco.Web/Models/DynamicPublishedContent.cs b/src/Umbraco.Web/Models/DynamicPublishedContent.cs
index 107c20b70f..c41fd4b540 100644
--- a/src/Umbraco.Web/Models/DynamicPublishedContent.cs
+++ b/src/Umbraco.Web/Models/DynamicPublishedContent.cs
@@ -54,111 +54,47 @@ namespace Umbraco.Web.Models
///
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?
- result = typeof(DynamicPublishedContent).InvokeMember(binder.Name,
- System.Reflection.BindingFlags.Instance |
- System.Reflection.BindingFlags.Public |
- System.Reflection.BindingFlags.GetProperty,
- null,
- this,
- args);
- return true;
- }
- catch (MissingMethodException)
- {
- try
- {
- //Static or Instance Method?
- result = typeof(DynamicPublishedContent).InvokeMember(binder.Name,
- System.Reflection.BindingFlags.Instance |
- System.Reflection.BindingFlags.Public |
- System.Reflection.BindingFlags.Static |
- System.Reflection.BindingFlags.InvokeMethod,
- null,
- this,
- args);
- return true;
- }
- catch (MissingMethodException)
- {
- try
- {
- result = ExecuteExtensionMethod(args, binder.Name);
- return true;
- }
- catch (TargetInvocationException)
- {
- result = new DynamicNull();
- return true;
- }
-
- catch
- {
- //TODO: LOg this!
-
- result = null;
- return false;
- }
-
- }
-
-
- }
- catch
- {
- result = null;
- return false;
- }
-
- }
-
- private object ExecuteExtensionMethod(object[] args, string name)
- {
- object result = null;
-
- var methodTypesToFind = new[]
+ var attempt = DynamicInstanceHelper.TryInvokeMember(this, binder, args, new[]
{
typeof(DynamicPublishedContent)
- };
+ });
- //find known extension methods that match the first type in the list
- MethodInfo toExecute = null;
- foreach (var t in methodTypesToFind)
+ if (attempt.Success)
{
- toExecute = ExtensionMethodFinder.FindExtensionMethod(t, args, name, false);
- if (toExecute != null)
- break;
- }
+ result = attempt.Result.ObjectResult;
- if (toExecute != null)
- {
- var genericArgs = (new[] { this }).Concat(args);
- result = toExecute.Invoke(null, genericArgs.ToArray());
- }
- else
- {
- throw new MissingMethodException();
- }
- if (result != null)
- {
- if (result is IPublishedContent)
- {
- result = new DynamicPublishedContent((IPublishedContent)result);
- }
- if (result is IEnumerable)
- {
- result = new DynamicPublishedContentList((IEnumerable)result);
+ //need to check the return type and possibly cast if result is from an extension method found
+ if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod)
+ {
+ if (attempt.Result.ObjectResult != null)
+ {
+ if (attempt.Result.ObjectResult is IPublishedContent)
+ {
+ result = new DynamicPublishedContent((IPublishedContent)attempt.Result.ObjectResult);
+ }
+ if (attempt.Result.ObjectResult is IEnumerable)
+ {
+ result = new DynamicPublishedContentList((IEnumerable)attempt.Result.ObjectResult);
+ }
+ if (attempt.Result.ObjectResult is IEnumerable)
+ {
+ result = new DynamicPublishedContentList((IEnumerable)attempt.Result.ObjectResult);
+ }
+ }
}
- if (result is IEnumerable)
- {
- result = new DynamicPublishedContentList((IEnumerable)result);
- }
+ return true;
}
- return result;
+
+ //this is the result of an extension method execution gone wrong so we return dynamic null
+ if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod
+ && attempt.Error != null && attempt.Error is TargetInvocationException)
+ {
+ result = new DynamicNull();
+ return true;
+ }
+
+ result = null;
+ return false;
}
///
diff --git a/src/Umbraco.Web/Models/DynamicPublishedContentList.cs b/src/Umbraco.Web/Models/DynamicPublishedContentList.cs
index 7740a485fd..94d32dade3 100644
--- a/src/Umbraco.Web/Models/DynamicPublishedContentList.cs
+++ b/src/Umbraco.Web/Models/DynamicPublishedContentList.cs
@@ -46,9 +46,6 @@ namespace Umbraco.Web.Models
}
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!
-
//TODO: Nowhere here are we checking if args is the correct length!
//NOTE: For many of these we could actually leave them out since we are executing custom extension methods and because
@@ -196,11 +193,6 @@ namespace Umbraco.Web.Models
{
result = new DynamicPublishedContentList(this.Items.Except(firstArg as IEnumerable, new DynamicPublishedContentIdEqualityComparer()));
return true;
- }
- if ((firstArg as DynamicPublishedContentList) != null)
- {
- result = new DynamicPublishedContentList(this.Items.Except((firstArg as DynamicPublishedContentList).Items, new DynamicPublishedContentIdEqualityComparer()));
- return true;
}
}
if (name == "Intersect")
@@ -209,11 +201,6 @@ namespace Umbraco.Web.Models
{
result = new DynamicPublishedContentList(this.Items.Intersect(firstArg as IEnumerable, new DynamicPublishedContentIdEqualityComparer()));
return true;
- }
- if ((firstArg as DynamicPublishedContentList) != null)
- {
- result = new DynamicPublishedContentList(this.Items.Intersect((firstArg as DynamicPublishedContentList).Items, new DynamicPublishedContentIdEqualityComparer()));
- return true;
}
}
if (name == "Distinct")
@@ -226,65 +213,50 @@ namespace Umbraco.Web.Models
result = Pluck(args);
return true;
}
- try
- {
- //Property?
- result = Items.GetType().InvokeMember(binder.Name,
- System.Reflection.BindingFlags.Instance |
- System.Reflection.BindingFlags.Public |
- System.Reflection.BindingFlags.GetProperty,
- null,
- Items,
- args);
- return true;
- }
- catch (MissingMethodException)
- {
- try
- {
- //Static or Instance Method?
- result = Items.GetType().InvokeMember(binder.Name,
- System.Reflection.BindingFlags.Instance |
- System.Reflection.BindingFlags.Public |
- System.Reflection.BindingFlags.Static |
- System.Reflection.BindingFlags.InvokeMethod,
- null,
- Items,
- args);
- return true;
- }
- catch (MissingMethodException)
- {
- try
- {
- result = ExecuteExtensionMethod(args, name);
- return true;
- }
- catch (TargetInvocationException)
- {
- //We do this to enable error checking of Razor Syntax when a method e.g. ElementAt(2) is used.
- //When the Script is tested, there's no Children which means ElementAt(2) is invalid (IndexOutOfRange)
- //Instead, we are going to return DynamicNull;
- result = new DynamicNull();
- return true;
- }
+ //ok, now lets try to match by member, property, extensino method
+ var attempt = DynamicInstanceHelper.TryInvokeMember(this, binder, args, new[]
+ {
+ typeof (IEnumerable),
+ typeof (DynamicPublishedContentList)
+ });
- catch
- {
- result = null;
- return false;
- }
+ if (attempt.Success)
+ {
+ result = attempt.Result.ObjectResult;
- }
+ //need to check the return type and possibly cast if result is from an extension method found
+ if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod)
+ {
+ if (attempt.Result.ObjectResult != null)
+ {
+ if (attempt.Result.ObjectResult is IPublishedContent)
+ {
+ result = new DynamicPublishedContent((IPublishedContent)attempt.Result.ObjectResult);
+ }
+ if (attempt.Result.ObjectResult is IEnumerable)
+ {
+ result = new DynamicPublishedContentList((IEnumerable)attempt.Result.ObjectResult);
+ }
+ if (attempt.Result.ObjectResult is IEnumerable)
+ {
+ result = new DynamicPublishedContentList((IEnumerable)attempt.Result.ObjectResult);
+ }
+ }
+ }
+ return true;
+ }
+ //this is the result of an extension method execution gone wrong so we return dynamic null
+ if (attempt.Result.Reason == DynamicInstanceHelper.TryInvokeMemberSuccessReason.FoundExtensionMethod
+ && attempt.Error != null && attempt.Error is TargetInvocationException)
+ {
+ result = new DynamicNull();
+ return true;
+ }
- }
- catch
- {
- result = null;
- return false;
- }
+ result = null;
+ return false;
}
private T Aggregate(IEnumerable data, string name) where T : struct
@@ -425,67 +397,7 @@ namespace Umbraco.Web.Models
}
return result;
}
-
- private object ExecuteExtensionMethod(object[] args, string name)
- {
- object result = null;
-
- var methodTypesToFind = new[]
- {
- typeof(IEnumerable),
- typeof(DynamicPublishedContentList)
- };
-
- //find known extension methods that match the first type in the list
- MethodInfo toExecute = null;
- foreach(var t in methodTypesToFind)
- {
- toExecute = ExtensionMethodFinder.FindExtensionMethod(t, args, name, false);
- if (toExecute != null)
- break;
- }
-
- if (toExecute != null)
- {
- if (toExecute.GetParameters().First().ParameterType == typeof(DynamicPublishedContentList))
- {
- var genericArgs = (new[] { this }).Concat(args);
- result = toExecute.Invoke(null, genericArgs.ToArray());
- }
- else if (TypeHelper.IsTypeAssignableFrom(toExecute.GetParameters().First().ParameterType))
- {
- //if it is IQueryable, we'll need to cast Items AsQueryable
- var genericArgs = (new[] { Items.AsQueryable() }).Concat(args);
- result = toExecute.Invoke(null, genericArgs.ToArray());
- }
- else
- {
- var genericArgs = (new[] { Items }).Concat(args);
- result = toExecute.Invoke(null, genericArgs.ToArray());
- }
- }
- else
- {
- throw new MissingMethodException();
- }
- if (result != null)
- {
- if (result is IPublishedContent)
- {
- result = new DynamicPublishedContent((IPublishedContent)result);
- }
- if (result is IEnumerable)
- {
- result = new DynamicPublishedContentList((IEnumerable)result);
- }
- if (result is IEnumerable)
- {
- result = new DynamicPublishedContentList((IEnumerable)result);
- }
- }
- return result;
- }
-
+
public T Single(string predicate, params object[] values)
{
return predicate.IsNullOrWhiteSpace()
diff --git a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicXml.cs b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicXml.cs
index fa45127c52..1eff680b30 100644
--- a/src/umbraco.MacroEngines/RazorDynamicNode/DynamicXml.cs
+++ b/src/umbraco.MacroEngines/RazorDynamicNode/DynamicXml.cs
@@ -11,8 +11,8 @@ using System.Web;
namespace umbraco.MacroEngines
{
- [Obsolete("This class has been superceded by Umbraco.Core.Dynamics.DynamicXml")]
- public class DynamicXml : DynamicObject, IEnumerable
+ [Obsolete("This class has been superceded by Umbraco.Core.Dynamics.DynamicXml")]
+ public class DynamicXml : DynamicObject, IEnumerable, IEnumerable
{
private readonly Umbraco.Core.Dynamics.DynamicXml _inner;
@@ -92,10 +92,21 @@ namespace umbraco.MacroEngines
return new DynamicXml(_inner.BaseElement.XPathSelectElements(expression).FirstOrDefault());
}
- public IEnumerator GetEnumerator()
- {
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return this.BaseElement.Elements().GetEnumerator();
+ }
+
+ public IEnumerator GetEnumerator()
+ {
return this.BaseElement.Elements().Select(e => new DynamicXml(e)).GetEnumerator();
- }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
public int Count()
{
return _inner.Count();
@@ -115,6 +126,16 @@ namespace umbraco.MacroEngines
return _inner.HasValue();
}
+ public IEnumerable Take(int count)
+ {
+ return _inner.Take(count).Select(x => new DynamicXml(x.BaseElement));
+ }
+
+ public IEnumerable Skip(int count)
+ {
+ return _inner.Skip(count).Select(x => new DynamicXml(x.BaseElement));
+ }
+
public bool IsFirst()
{
return _inner.IsFirst();