mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-07-16 01:05:07 +08:00
Updating ReflectOn.NameOf to support indexer calls
This is so that we can write stuff like this in aspx pages: name="<%=Html.NameOf(m => m.PageEntries[pageIndex].PageId)%>" --HG-- extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4038939
This commit is contained in:
parent
72851737cc
commit
ace78cfd33
@ -130,6 +130,8 @@
|
||||
<Compile Include="Records\Foo.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Stubs\StubHttpContext.cs" />
|
||||
<Compile Include="Utility\ReflectOnTests.cs" />
|
||||
<Compile Include="Utility\ReflectTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Orchard\Orchard.csproj">
|
||||
|
74
src/Orchard.Tests/Utility/ReflectOnTests.cs
Normal file
74
src/Orchard.Tests/Utility/ReflectOnTests.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using NUnit.Framework;
|
||||
using Orchard.Utility;
|
||||
|
||||
namespace Orchard.Tests.Utility {
|
||||
[TestFixture]
|
||||
public class ReflectOnTests {
|
||||
#region Setup/Teardown
|
||||
|
||||
[TestFixtureSetUp]
|
||||
public void InitFixture() {
|
||||
}
|
||||
|
||||
[TestFixtureTearDown]
|
||||
public void TermFixture() {
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private class TestClass {
|
||||
public int MyField;
|
||||
public int MyField2;
|
||||
public int MyProperty { get { MyField = 5; return MyField; } }
|
||||
public int MyProperty2 { get { MyField2 = 5; return MyField2; } }
|
||||
public void MyMethod(int i) { }
|
||||
public int MyMethod(string s) { return 5; }
|
||||
public void MyMethod2(int i) { }
|
||||
public int MyMethod2(string s) { return 5; }
|
||||
public TestClass MyTestClass { get { return null; } }
|
||||
public TestClass this[int i] { get { return null; } }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReflectOnGetMemberShouldReturnCorrectMemberInfo() {
|
||||
Assert.That(ReflectOn<TestClass>.GetMember(p => p.MyField).Name, Is.EqualTo("MyField"));
|
||||
Assert.That(ReflectOn<TestClass>.GetMember(p => p.MyMethod(5)).Name, Is.EqualTo("MyMethod"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReflectOnShouldWorkOnFields() {
|
||||
Assert.That(ReflectOn<TestClass>.GetField(p => p.MyField).Name, Is.EqualTo("MyField"));
|
||||
Assert.That(ReflectOn<TestClass>.GetField(p => p.MyField2).Name, Is.EqualTo("MyField2"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReflectOnShouldWorkOnProperties() {
|
||||
Assert.That(ReflectOn<TestClass>.GetProperty(p => p.MyProperty).Name, Is.EqualTo("MyProperty"));
|
||||
Assert.That(ReflectOn<TestClass>.GetProperty(p => p.MyProperty2).Name, Is.EqualTo("MyProperty2"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReflectOnShouldWorkOnMethods() {
|
||||
Assert.That(ReflectOn<TestClass>.GetMethod(p => p.MyMethod(5)).Name, Is.EqualTo("MyMethod"));
|
||||
Assert.That(ReflectOn<TestClass>.GetMethod(p => p.MyMethod("")).Name, Is.EqualTo("MyMethod"));
|
||||
Assert.That(ReflectOn<TestClass>.GetMethod(p => p.MyMethod("")).ReturnType, Is.EqualTo(typeof(int)));
|
||||
|
||||
Assert.That(ReflectOn<TestClass>.GetMethod(p => p.MyMethod2(5)).Name, Is.EqualTo("MyMethod2"));
|
||||
Assert.That(ReflectOn<TestClass>.GetMethod(p => p.MyMethod2("")).Name, Is.EqualTo("MyMethod2"));
|
||||
Assert.That(ReflectOn<TestClass>.GetMethod(p => p.MyMethod2("")).ReturnType, Is.EqualTo(typeof(int)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReflectOnShouldWorkOnDottedProperties() {
|
||||
Assert.That(ReflectOn<TestClass>.NameOf(p => p.MyTestClass.MyTestClass.MyProperty), Is.EqualTo("MyTestClass.MyTestClass.MyProperty"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReflectOnShouldWorkOnIndexers() {
|
||||
Assert.That(ReflectOn<TestClass>.NameOf(p => p[0].MyTestClass[1].MyProperty), Is.EqualTo("[0].MyTestClass[1].MyProperty"));
|
||||
int j = 5;
|
||||
int index = j;
|
||||
Assert.That(ReflectOn<TestClass>.NameOf(p => p.MyTestClass[index].MyProperty), Is.EqualTo("MyTestClass[5].MyProperty"));
|
||||
}
|
||||
}
|
||||
}
|
47
src/Orchard.Tests/Utility/ReflectTests.cs
Normal file
47
src/Orchard.Tests/Utility/ReflectTests.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using NUnit.Framework;
|
||||
using Orchard.Utility;
|
||||
|
||||
namespace Orchard.Tests.Utility {
|
||||
[TestFixture]
|
||||
public class ReflectTests {
|
||||
private class TestClass {
|
||||
public static int MyField;
|
||||
public static int MyField2;
|
||||
public static int MyProperty { get { MyField = 5; return MyField; } }
|
||||
public static int MyProperty2 { get { MyField2 = 5; return MyField2; } }
|
||||
public static void MyMethod(int i) { }
|
||||
public static int MyMethod(string s) { return 5; }
|
||||
public static void MyMethod2(int i) { }
|
||||
public static int MyMethod2(string s) { return 5; }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReflectGetMemberShouldReturnCorrectMemberInfo() {
|
||||
Assert.That(Reflect.GetMember(() => TestClass.MyField).Name, Is.EqualTo("MyField"));
|
||||
Assert.That(Reflect.GetMember(() => TestClass.MyMethod(5)).Name, Is.EqualTo("MyMethod"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReflectShouldWorkOnFields() {
|
||||
Assert.That(Reflect.GetField(() => TestClass.MyField).Name, Is.EqualTo("MyField"));
|
||||
Assert.That(Reflect.GetField(() => TestClass.MyField2).Name, Is.EqualTo("MyField2"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReflectShouldWorkOnProperties() {
|
||||
Assert.That(Reflect.GetProperty(() => TestClass.MyProperty).Name, Is.EqualTo("MyProperty"));
|
||||
Assert.That(Reflect.GetProperty(() => TestClass.MyProperty2).Name, Is.EqualTo("MyProperty2"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReflectShouldWorkOnMethods() {
|
||||
Assert.That(Reflect.GetMethod(() => TestClass.MyMethod(5)).Name, Is.EqualTo("MyMethod"));
|
||||
Assert.That(Reflect.GetMethod(() => TestClass.MyMethod("")).Name, Is.EqualTo("MyMethod"));
|
||||
Assert.That(Reflect.GetMethod(() => TestClass.MyMethod("")).ReturnType, Is.EqualTo(typeof(int)));
|
||||
|
||||
Assert.That(Reflect.GetMethod(() => TestClass.MyMethod2(5)).Name, Is.EqualTo("MyMethod2"));
|
||||
Assert.That(Reflect.GetMethod(() => TestClass.MyMethod2("")).Name, Is.EqualTo("MyMethod2"));
|
||||
Assert.That(Reflect.GetMethod(() => TestClass.MyMethod2("")).ReturnType, Is.EqualTo(typeof(int)));
|
||||
}
|
||||
}
|
||||
}
|
@ -36,10 +36,8 @@
|
||||
int pageIndex = 0;
|
||||
foreach (var pageEntry in Model.PageEntries.Where(e => e.IsChecked)) {
|
||||
%>
|
||||
<%--TODO: Use "NameOf" when it supports these expressions--%>
|
||||
<input type="hidden" value="<%=pageEntry.PageId %>" name="<%=string.Format("PageEntries[{0}].PageId", pageIndex)%>"/>
|
||||
<input type="hidden" value="<%=pageEntry.IsChecked %>" name="<%=string.Format("PageEntries[{0}].IsChecked", pageIndex)%>"/>
|
||||
|
||||
<input type="hidden" value="<%=pageEntry.PageId %>" name="<%=Html.NameOf(m => m.PageEntries[pageIndex].PageId)%>"/>
|
||||
<input type="hidden" value="<%=pageEntry.IsChecked %>" name="<%=Html.NameOf(m => m.PageEntries[pageIndex].IsChecked)%>"/>
|
||||
<% pageIndex++;
|
||||
}%>
|
||||
<%}/*EndForm*/%>
|
||||
|
@ -35,9 +35,8 @@
|
||||
int pageIndex = 0;
|
||||
foreach (var pageEntry in Model.PageEntries.Where(e => e.IsChecked)) {
|
||||
%>
|
||||
<%--TODO: Use "NameOf" when it supports these expressions--%>
|
||||
<input type="hidden" value="<%=pageEntry.PageId %>" name="<%=string.Format("PageEntries[{0}].PageId", pageIndex)%>"/>
|
||||
<input type="hidden" value="<%=pageEntry.IsChecked %>" name="<%=string.Format("PageEntries[{0}].IsChecked", pageIndex)%>"/>
|
||||
<input type="hidden" value="<%=pageEntry.PageId %>" name="<%=Html.NameOf(m => m.PageEntries[pageIndex].PageId)%>"/>
|
||||
<input type="hidden" value="<%=pageEntry.IsChecked %>" name="<%=Html.NameOf(m => m.PageEntries[pageIndex].IsChecked)%>"/>
|
||||
<% pageIndex++;
|
||||
}%>
|
||||
</div>
|
||||
|
@ -99,9 +99,8 @@ string SplitDateTime(DateTime dt)
|
||||
%>
|
||||
<tr>
|
||||
<td>
|
||||
<%--TODO: Use "NameOf" when it supports these expressions--%>
|
||||
<input type="hidden" value="<%=Model.PageEntries[pageIndex].PageId %>" name="<%=string.Format("PageEntries[{0}].PageId", pageIndex)%>"/>
|
||||
<input type="checkbox" value="true" name="<%=string.Format("PageEntries[{0}].IsChecked", pageIndex)%>"/>
|
||||
<input type="hidden" value="<%=Model.PageEntries[pageIndex].PageId %>" name="<%=Html.NameOf(m => m.PageEntries[pageIndex].PageId)%>"/>
|
||||
<input type="checkbox" value="true" name="<%=Html.NameOf(m => m.PageEntries[pageIndex].IsChecked)%>"/>
|
||||
</td>
|
||||
<td>
|
||||
<% if (pageEntry.IsPublished) { %>
|
||||
|
@ -1,7 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Web.Mvc;
|
||||
using System.Text;
|
||||
using System.Linq;
|
||||
using Orchard.Validation;
|
||||
|
||||
namespace Orchard.Utility {
|
||||
@ -45,11 +48,11 @@ namespace Orchard.Utility {
|
||||
}
|
||||
|
||||
public static string NameOf<T>(T value, Expression<Action<T>> expression) {
|
||||
return GetNameOf(expression.Body);
|
||||
return GetNameOf(expression);
|
||||
}
|
||||
|
||||
public static string NameOf<T, TResult>(T value, Expression<Func<T, TResult>> expression) {
|
||||
return GetNameOf(expression.Body);
|
||||
return GetNameOf(expression);
|
||||
}
|
||||
|
||||
internal static MemberInfo GetMemberInfo(LambdaExpression lambda) {
|
||||
@ -76,18 +79,108 @@ namespace Orchard.Utility {
|
||||
return memberExpression;
|
||||
}
|
||||
|
||||
internal static string GetNameOf(Expression expression) {
|
||||
MemberExpression memberExpression = GetMemberExpression(expression);
|
||||
if (memberExpression == null) {
|
||||
LambdaExpression lambda = expression as LambdaExpression;
|
||||
if (lambda == null)
|
||||
return null;
|
||||
return GetMemberInfo(lambda).Name;
|
||||
internal static void AddNames(Expression expression, NameBuilder nb) {
|
||||
if (expression == null)
|
||||
return;
|
||||
|
||||
switch (expression.NodeType) {
|
||||
case ExpressionType.MemberAccess:
|
||||
var memberExpression = (MemberExpression)expression;
|
||||
AddNames(memberExpression.Expression, nb);
|
||||
if (nb.DotNeeded)
|
||||
nb.Append(".");
|
||||
nb.Append(memberExpression.Member.Name);
|
||||
break;
|
||||
|
||||
//case ExpressionType.Convert:
|
||||
// var unaryExpression = (UnaryExpression)expression;
|
||||
// AddNames(unaryExpression.Operand, nb);
|
||||
// break;
|
||||
|
||||
case ExpressionType.Call:
|
||||
var callExpression = (MethodCallExpression)expression;
|
||||
MethodInfo method = callExpression.Method;
|
||||
bool isIndexer = (method.Name == "get_Item" && method.IsSpecialName);
|
||||
if (!isIndexer) {
|
||||
goto default;
|
||||
}
|
||||
|
||||
AddNames(callExpression.Object, nb);
|
||||
nb.Append("[" + GetArguments(callExpression.Arguments).Aggregate((a, b) => a + b) + "]");
|
||||
break;
|
||||
|
||||
case ExpressionType.Parameter:
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException(
|
||||
string.Format("Unsupported expression type \"{0}\" in named expression", Enum.GetName(typeof(ExpressionType), expression.NodeType)));
|
||||
}
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetArguments(IEnumerable<Expression> expressions) {
|
||||
foreach (var expression in expressions) {
|
||||
object value = GetExpressionConstantValue(expression);
|
||||
string result = value == null ? null : value.ToString();
|
||||
yield return result;
|
||||
}
|
||||
}
|
||||
|
||||
private static object GetExpressionConstantValue(Expression expression) {
|
||||
switch (expression.NodeType) {
|
||||
case ExpressionType.Constant:
|
||||
var constantExpression = (ConstantExpression)expression;
|
||||
return constantExpression.Value;
|
||||
|
||||
case ExpressionType.MemberAccess:
|
||||
var memberExpression = (MemberExpression)expression;
|
||||
object value = GetExpressionConstantValue(memberExpression.Expression);
|
||||
if (value == null)
|
||||
throw new InvalidOperationException("Member access to \"null\" instance is not supported");
|
||||
|
||||
FieldInfo fieldInfo = memberExpression.Member as FieldInfo;
|
||||
if (fieldInfo != null){
|
||||
return fieldInfo.GetValue(value);
|
||||
}
|
||||
|
||||
PropertyInfo propertyInfo = memberExpression.Member as PropertyInfo;
|
||||
if (propertyInfo != null) {
|
||||
return propertyInfo.GetValue(value, null);
|
||||
}
|
||||
throw new InvalidOperationException(
|
||||
string.Format("Member access expression \"{0}\" not supported", memberExpression.GetType().FullName));
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException(
|
||||
string.Format("Unsupported expression type\"{0}\" in method or indexer argument", Enum.GetName(typeof(ExpressionType), expression.NodeType)));
|
||||
}
|
||||
}
|
||||
|
||||
internal static string GetNameOf(LambdaExpression expression) {
|
||||
var nb = new NameBuilder(expression);
|
||||
AddNames(expression.Body, nb);
|
||||
return nb.ToString();
|
||||
}
|
||||
|
||||
internal class NameBuilder {
|
||||
private readonly StringBuilder _stringBuilder = new StringBuilder();
|
||||
private readonly LambdaExpression _expression;
|
||||
|
||||
public NameBuilder(LambdaExpression expression) {
|
||||
_expression = expression;
|
||||
}
|
||||
|
||||
public override string ToString() {
|
||||
return _stringBuilder.ToString();
|
||||
}
|
||||
|
||||
public bool DotNeeded {
|
||||
get { return _stringBuilder.Length > 0; }
|
||||
}
|
||||
|
||||
public void Append(string s) {
|
||||
_stringBuilder.Append(s);
|
||||
}
|
||||
string parentName = GetNameOf(memberExpression.Expression);
|
||||
if (parentName == null)
|
||||
return memberExpression.Member.Name;
|
||||
return parentName + "." + memberExpression.Member.Name;
|
||||
}
|
||||
}
|
||||
}
|
@ -50,11 +50,11 @@ namespace Orchard.Utility {
|
||||
}
|
||||
|
||||
public static string NameOf(Expression<Action<T>> expression) {
|
||||
return Reflect.GetNameOf(expression.Body);
|
||||
return Reflect.GetNameOf(expression);
|
||||
}
|
||||
|
||||
public static string NameOf<TResult>(Expression<Func<T, TResult>> expression) {
|
||||
return Reflect.GetNameOf(expression.Body);
|
||||
return Reflect.GetNameOf(expression);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user