99 lines
4.1 KiB
C#
99 lines
4.1 KiB
C#
// Copyright (c) .NET Foundation. All rights reserved.
|
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
|
|
|
using System;
|
|
using System.Globalization;
|
|
using System.Linq.Expressions;
|
|
|
|
namespace Microsoft.AspNet.JsonPatch.Helpers
|
|
{
|
|
internal static class ExpressionHelpers
|
|
{
|
|
public static string GetPath<TModel, TProp>(Expression<Func<TModel, TProp>> expr) where TModel : class
|
|
{
|
|
return "/" + GetPath(expr.Body, true);
|
|
}
|
|
|
|
private static string GetPath(Expression expr, bool firstTime)
|
|
{
|
|
switch (expr.NodeType)
|
|
{
|
|
case ExpressionType.ArrayIndex:
|
|
var binaryExpression = (BinaryExpression)expr;
|
|
|
|
if (ContinueWithSubPath(binaryExpression.Left.NodeType, false))
|
|
{
|
|
var leftFromBinaryExpression = GetPath(binaryExpression.Left, false);
|
|
return leftFromBinaryExpression + "/" + binaryExpression.Right.ToString();
|
|
}
|
|
else
|
|
{
|
|
return binaryExpression.Right.ToString();
|
|
}
|
|
case ExpressionType.Call:
|
|
var methodCallExpression = (MethodCallExpression)expr;
|
|
|
|
if (ContinueWithSubPath(methodCallExpression.Object.NodeType, false))
|
|
{
|
|
var leftFromMemberCallExpression = GetPath(methodCallExpression.Object, false);
|
|
return leftFromMemberCallExpression + "/" +
|
|
GetIndexerInvocation(methodCallExpression.Arguments[0]);
|
|
}
|
|
else
|
|
{
|
|
return GetIndexerInvocation(methodCallExpression.Arguments[0]);
|
|
}
|
|
case ExpressionType.Convert:
|
|
return GetPath(((UnaryExpression)expr).Operand, false);
|
|
case ExpressionType.MemberAccess:
|
|
var memberExpression = expr as MemberExpression;
|
|
|
|
if (ContinueWithSubPath(memberExpression.Expression.NodeType, false))
|
|
{
|
|
var left = GetPath(memberExpression.Expression, false);
|
|
return left + "/" + memberExpression.Member.Name;
|
|
}
|
|
else
|
|
{
|
|
return memberExpression.Member.Name;
|
|
}
|
|
case ExpressionType.Parameter:
|
|
// Fits "x => x" (the whole document which is "" as JSON pointer)
|
|
return firstTime ? string.Empty : null;
|
|
default:
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
private static bool ContinueWithSubPath(ExpressionType expressionType, bool firstTime)
|
|
{
|
|
if (firstTime)
|
|
{
|
|
return (expressionType == ExpressionType.ArrayIndex
|
|
|| expressionType == ExpressionType.Call
|
|
|| expressionType == ExpressionType.Convert
|
|
|| expressionType == ExpressionType.MemberAccess
|
|
|| expressionType == ExpressionType.Parameter);
|
|
}
|
|
else
|
|
{
|
|
return (expressionType == ExpressionType.ArrayIndex
|
|
|| expressionType == ExpressionType.Call
|
|
|| expressionType == ExpressionType.Convert
|
|
|| expressionType == ExpressionType.MemberAccess);
|
|
}
|
|
}
|
|
|
|
private static string GetIndexerInvocation(Expression expression)
|
|
{
|
|
var converted = Expression.Convert(expression, typeof(object));
|
|
var fakeParameter = Expression.Parameter(typeof(object), null);
|
|
var lambda = Expression.Lambda<Func<object, object>>(converted, fakeParameter);
|
|
Func<object, object> func;
|
|
|
|
func = lambda.Compile();
|
|
|
|
return Convert.ToString(func(null), CultureInfo.InvariantCulture);
|
|
}
|
|
}
|
|
} |