Fixes threading issue with Dynamicexpression... would have caused some strange behavior in the past!
Fixes: U4-995 - most methods will now work in dynamic expressions
This commit is contained in:
@@ -9,10 +9,11 @@ using System.Linq.Expressions;
|
||||
|
||||
namespace Umbraco.Core.Dynamics
|
||||
{
|
||||
/// <summary>
|
||||
/// Utility class for finding extension methods on a type to execute
|
||||
/// </summary>
|
||||
internal static class ExtensionMethodFinder
|
||||
{
|
||||
|
||||
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns all extension methods found matching the definition
|
||||
/// </summary>
|
||||
@@ -22,7 +23,7 @@ namespace Umbraco.Core.Dynamics
|
||||
/// <param name="argsContainsThis"></param>
|
||||
/// <returns></returns>
|
||||
/// <remarks>
|
||||
/// NOTE: This will be an intensive method to call!! Results should be cached!
|
||||
/// TODO: NOTE: This will be an intensive method to call!! Results should be cached!
|
||||
/// </remarks>
|
||||
private static IEnumerable<MethodInfo> GetAllExtensionMethods(Type thisType, string name, int argumentCount, bool argsContainsThis)
|
||||
{
|
||||
@@ -62,7 +63,8 @@ namespace Umbraco.Core.Dynamics
|
||||
|
||||
return methodsWhereArgZeroIsTargetType.Select(mt => mt.m);
|
||||
}
|
||||
private static bool MethodArgZeroHasCorrectTargetType(MethodInfo method, Type firstArgumentType, Type thisType)
|
||||
|
||||
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
|
||||
@@ -112,7 +114,8 @@ namespace Umbraco.Core.Dynamics
|
||||
bool result = (thisType == firstArgumentType);
|
||||
return result;
|
||||
}
|
||||
private static Type FirstParameterType(MethodInfo m)
|
||||
|
||||
private static Type FirstParameterType(MethodInfo m)
|
||||
{
|
||||
ParameterInfo[] p = m.GetParameters();
|
||||
if (p.Any())
|
||||
@@ -122,71 +125,74 @@ namespace Umbraco.Core.Dynamics
|
||||
return null;
|
||||
}
|
||||
|
||||
private static MethodInfo DetermineMethodFromParams(IEnumerable<MethodInfo> methods, Type genericType, IEnumerable<object> args)
|
||||
{
|
||||
if (!methods.Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
MethodInfo methodToExecute = null;
|
||||
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 =>
|
||||
{
|
||||
var oe = (o as Expression);
|
||||
if (oe != null)
|
||||
{
|
||||
return oe.Type.FullName;
|
||||
}
|
||||
return o.GetType().FullName;
|
||||
});
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (methodToExecute == null)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var firstGenericMethod = methods.FirstOrDefault(x => x.IsGenericMethodDefinition);
|
||||
if (firstGenericMethod != null)
|
||||
{
|
||||
firstMethod = firstGenericMethod;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstMethod != null)
|
||||
{
|
||||
if (firstMethod.IsGenericMethodDefinition)
|
||||
{
|
||||
if (genericType != null)
|
||||
{
|
||||
methodToExecute = firstMethod.MakeGenericMethod(genericType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
methodToExecute = firstMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
return methodToExecute;
|
||||
}
|
||||
|
||||
public static MethodInfo FindExtensionMethod(Type thisType, object[] args, string name, bool argsContainsThis)
|
||||
{
|
||||
Type genericType = null;
|
||||
if (thisType.IsGenericType)
|
||||
{
|
||||
genericType = thisType.GetGenericArguments()[0];
|
||||
}
|
||||
}
|
||||
|
||||
var methods = GetAllExtensionMethods(thisType, name, args.Length, argsContainsThis)
|
||||
.ToArray();
|
||||
|
||||
if (!methods.Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
MethodInfo methodToExecute = null;
|
||||
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 =>
|
||||
{
|
||||
var oe = (o as Expression);
|
||||
if (oe != null)
|
||||
{
|
||||
return oe.Type.FullName;
|
||||
}
|
||||
return o.GetType().FullName;
|
||||
});
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (methodToExecute == null)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var firstGenericMethod = methods.FirstOrDefault(x => x.IsGenericMethodDefinition);
|
||||
if (firstGenericMethod != null)
|
||||
{
|
||||
firstMethod = firstGenericMethod;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstMethod != null)
|
||||
{
|
||||
if (firstMethod.IsGenericMethodDefinition)
|
||||
{
|
||||
if (genericType != null)
|
||||
{
|
||||
methodToExecute = firstMethod.MakeGenericMethod(genericType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
methodToExecute = firstMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
return methodToExecute;
|
||||
var methods = GetAllExtensionMethods(thisType, name, args.Length, argsContainsThis).ToArray();
|
||||
return DetermineMethodFromParams(methods, genericType, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,18 +135,85 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Complex_Linq()
|
||||
public void String_ContainsValue_Extension_Method()
|
||||
{
|
||||
var doc = GetDynamicNode(1173);
|
||||
|
||||
var doc = GetDynamicNode(1046);
|
||||
|
||||
var result = doc.Ancestors().OrderBy("level")
|
||||
.Single()
|
||||
.Descendants()
|
||||
.Where("selectedNodes != null && selectedNodes != \"\" && selectedNodes.Split(new char[] {','}).Contains(\"1173\")")
|
||||
var paramVals = new Dictionary<string, object> { { "searchId", 1173 } }; //this is an integer value
|
||||
var result = doc.Children()
|
||||
.Where("selectedNodes.ContainsValue(searchId)", paramVals) //call an extension method
|
||||
.FirstOrDefault();
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(4444, result.Id);
|
||||
|
||||
//don't find!
|
||||
paramVals = new Dictionary<string, object> { { "searchId", 1111777 } };
|
||||
result = doc.Children()
|
||||
.Where("selectedNodes.ContainsValue(searchId)", paramVals)
|
||||
.FirstOrDefault();
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsTrue(result.GetType() == typeof(DynamicNull) || result.GetType() == typeof(umbraco.MacroEngines.DynamicNull));
|
||||
//Assert.AreEqual(typeof(DynamicNull), result.GetType());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void String_Contains_Method()
|
||||
{
|
||||
var doc = GetDynamicNode(1046);
|
||||
|
||||
var paramVals = new Dictionary<string, object> { { "searchId", "1173" } };
|
||||
var result = doc.Children()
|
||||
.Where("selectedNodes.Contains(searchId)", paramVals)
|
||||
.FirstOrDefault();
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(4444, result.Id);
|
||||
|
||||
//don't find!
|
||||
paramVals = new Dictionary<string, object> { { "searchId", "1aaa173" } };
|
||||
result = doc.Children()
|
||||
.Where("selectedNodes.Contains(searchId)", paramVals)
|
||||
.FirstOrDefault();
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.IsTrue(result.GetType() == typeof (DynamicNull) || result.GetType() == typeof (umbraco.MacroEngines.DynamicNull));
|
||||
//Assert.AreEqual(typeof (DynamicNull), result.GetType());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void String_Split_Method()
|
||||
{
|
||||
var doc = GetDynamicNode(1046);
|
||||
|
||||
var paramVals = new Dictionary<string, object>
|
||||
{
|
||||
{ "splitTerm", new char[] { ',' } },
|
||||
{ "splitOptions", StringSplitOptions.RemoveEmptyEntries }
|
||||
};
|
||||
var result = doc.Children()
|
||||
.Where("selectedNodes.Split(splitTerm, splitOptions).Length == 3", paramVals)
|
||||
.FirstOrDefault();
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(4444, result.Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Complex_Linq()
|
||||
{
|
||||
var doc = GetDynamicNode(1173);
|
||||
|
||||
var paramVals = new Dictionary<string, object> {{"splitTerm", new char[] {','}}, {"searchId", "1173"}};
|
||||
var result = doc.Ancestors().OrderBy("level")
|
||||
.Single()
|
||||
.Descendants()
|
||||
.Where("selectedNodes != null && selectedNodes != String.Empty && selectedNodes.Split(splitTerm).Contains(searchId)", paramVals)
|
||||
.FirstOrDefault();
|
||||
|
||||
Assert.IsNotNull(result);
|
||||
Assert.AreEqual(4444, result.Id);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -557,6 +624,16 @@ namespace Umbraco.Tests.DynamicDocument
|
||||
|
||||
Assert.AreEqual((int) 1174, (int) result.Id);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods used in tests
|
||||
/// </summary>
|
||||
public static class TestExtensionMethods
|
||||
{
|
||||
public static bool ContainsValue(this string s, int val)
|
||||
{
|
||||
return s.Contains(val.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,12 @@ namespace Umbraco.Web.Dynamics
|
||||
{
|
||||
internal static class DynamicExpression
|
||||
{
|
||||
public static bool ConvertDynamicNullToBooleanFalse = false;
|
||||
//public static bool ConvertDynamicNullToBooleanFalse = false;
|
||||
|
||||
public static Expression Parse<T>(Type resultType, string expression, bool convertDynamicNullToBooleanFalse, params object[] values)
|
||||
{
|
||||
ConvertDynamicNullToBooleanFalse = convertDynamicNullToBooleanFalse;
|
||||
var parser = new ExpressionParser<T>(null, expression, values);
|
||||
//ConvertDynamicNullToBooleanFalse = convertDynamicNullToBooleanFalse;
|
||||
var parser = new ExpressionParser<T>(null, expression, values, convertDynamicNullToBooleanFalse);
|
||||
return parser.Parse(resultType);
|
||||
}
|
||||
|
||||
@@ -22,8 +23,8 @@ namespace Umbraco.Web.Dynamics
|
||||
|
||||
public static LambdaExpression ParseLambda<T>(ParameterExpression[] parameters, Type resultType, string expression, bool convertDynamicNullToBooleanFalse, params object[] values)
|
||||
{
|
||||
ConvertDynamicNullToBooleanFalse = convertDynamicNullToBooleanFalse;
|
||||
var parser = new ExpressionParser<T>(parameters, expression, values);
|
||||
//ConvertDynamicNullToBooleanFalse = convertDynamicNullToBooleanFalse;
|
||||
var parser = new ExpressionParser<T>(parameters, expression, values, convertDynamicNullToBooleanFalse);
|
||||
return Expression.Lambda(parser.Parse(resultType), parameters);
|
||||
}
|
||||
|
||||
|
||||
@@ -197,7 +197,7 @@ namespace Umbraco.Web.Dynamics
|
||||
|
||||
ParameterExpression[] parameters = new ParameterExpression[] {
|
||||
Expression.Parameter(source.ElementType, "") };
|
||||
var parser = new ExpressionParser<T>(parameters, ordering, values);
|
||||
var parser = new ExpressionParser<T>(parameters, ordering, values, false);
|
||||
IEnumerable<DynamicOrdering> orderings = parser.ParseOrdering();
|
||||
Expression queryExpr = source.Expression;
|
||||
string methodAsc = "OrderBy";
|
||||
|
||||
@@ -200,12 +200,13 @@ namespace Umbraco.Web.Dynamics
|
||||
Dictionary<Expression, string> literals;
|
||||
ParameterExpression it;
|
||||
string text;
|
||||
private readonly bool _flagConvertDynamicNullToBooleanFalse;
|
||||
int textPos;
|
||||
int textLen;
|
||||
char ch;
|
||||
Token token;
|
||||
|
||||
public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values)
|
||||
public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values, bool flagConvertDynamicNullToBooleanFalse)
|
||||
{
|
||||
if (expression == null) throw new ArgumentNullException("expression");
|
||||
if (keywords == null) keywords = CreateKeywords();
|
||||
@@ -214,6 +215,7 @@ namespace Umbraco.Web.Dynamics
|
||||
if (parameters != null) ProcessParameters(parameters);
|
||||
if (values != null) ProcessValues(values);
|
||||
text = expression;
|
||||
_flagConvertDynamicNullToBooleanFalse = flagConvertDynamicNullToBooleanFalse;
|
||||
textLen = text.Length;
|
||||
SetTextPos(0);
|
||||
NextToken();
|
||||
@@ -839,6 +841,11 @@ namespace Umbraco.Web.Dynamics
|
||||
|
||||
Expression ParseMemberAccess(Type type, Expression instance)
|
||||
{
|
||||
//NOTE: SD: There is a lot of string checking going on here and I'm 99% sure this can all be done better
|
||||
// in a more generic sense to support any types with any extension methods, etc...
|
||||
// Too bad whoever wrote this decided not to put any code comments in :(
|
||||
// This is how to support method calls, etc... in dynamic statements.
|
||||
|
||||
if (instance != null) type = instance.Type;
|
||||
int errorPos = token.Pos;
|
||||
string id = GetIdentifier();
|
||||
@@ -864,17 +871,26 @@ namespace Umbraco.Web.Dynamics
|
||||
if (typeArgs[0] == typeof(T))
|
||||
{
|
||||
if (instance != null && instance is LambdaExpression)
|
||||
{
|
||||
{
|
||||
//not sure why this is object or why we need to do this but if we change it, things die...
|
||||
//also not sure why it is changed to string, i think this might be to ensure string methods are supported
|
||||
//but seems to me that we then won't support other types of methods?
|
||||
if (typeArgs[1] == typeof(object))
|
||||
{
|
||||
instanceAsString = StringFormat(instance as LambdaExpression, instanceExpression);
|
||||
type = typeof(string);
|
||||
}
|
||||
if (typeArgs[1] == typeof(string))
|
||||
else if (typeArgs[1] == typeof(string))
|
||||
{
|
||||
instanceAsString = instance as LambdaExpression;
|
||||
type = typeof(string);
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// instanceAsString = instance as LambdaExpression;
|
||||
// type = typeArgs[1];
|
||||
//}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -882,6 +898,10 @@ namespace Umbraco.Web.Dynamics
|
||||
{
|
||||
case 0:
|
||||
//not found
|
||||
|
||||
//SD: I have yet to see extension methods actually being called in the dynamic parsing... need to unit test these
|
||||
// scenarios and figure out why all this type checking occurs.
|
||||
|
||||
if (type == typeof(string) && instanceAsString != null)
|
||||
{
|
||||
Expression[] newArgs = (new List<Expression>() { Expression.Invoke(instanceAsString, instanceExpression) }).Concat(args).ToArray();
|
||||
@@ -944,7 +964,7 @@ namespace Umbraco.Web.Dynamics
|
||||
BlockExpression block = Expression.Block(
|
||||
typeof(object),
|
||||
new[] { ignoreCase, binder, result, convertDynamicNullToBooleanFalse },
|
||||
Expression.Assign(convertDynamicNullToBooleanFalse, Expression.Constant(DynamicExpression.ConvertDynamicNullToBooleanFalse, typeof(bool))),
|
||||
Expression.Assign(convertDynamicNullToBooleanFalse, Expression.Constant(_flagConvertDynamicNullToBooleanFalse, typeof(bool))),
|
||||
Expression.Assign(ignoreCase, Expression.Constant(false, typeof(bool))),
|
||||
Expression.Assign(binder, Expression.New(getMemberBinderConstructor, Expression.Constant(id, typeof(string)), ignoreCase)),
|
||||
Expression.Assign(result, Expression.Constant(null)),
|
||||
@@ -981,7 +1001,7 @@ namespace Umbraco.Web.Dynamics
|
||||
BlockExpression block = Expression.Block(
|
||||
typeof(object),
|
||||
new[] { lambdaResult, result, idParam, convertDynamicNullToBooleanFalse },
|
||||
Expression.Assign(convertDynamicNullToBooleanFalse, Expression.Constant(DynamicExpression.ConvertDynamicNullToBooleanFalse, typeof(bool))),
|
||||
Expression.Assign(convertDynamicNullToBooleanFalse, Expression.Constant(_flagConvertDynamicNullToBooleanFalse, typeof(bool))),
|
||||
Expression.Assign(lambdaResult, Expression.Invoke(instance, lambdaInstanceExpression)),
|
||||
Expression.Assign(result, Expression.Call(ReflectPropertyValue, lambdaResult, Expression.Constant(id))),
|
||||
Expression.IfThen(
|
||||
@@ -1020,21 +1040,11 @@ namespace Umbraco.Web.Dynamics
|
||||
return null;
|
||||
}
|
||||
private static Expression CallMethodOnDynamicNode(Expression instance, Expression[] args, LambdaExpression instanceAsString, ParameterExpression instanceExpression, MethodInfo method, bool isStatic)
|
||||
{
|
||||
ConstantExpression defaultReturnValue = Expression.Constant(null, typeof(object));
|
||||
{
|
||||
Type methodReturnType = method.ReturnType;
|
||||
switch (methodReturnType.Name)
|
||||
{
|
||||
case "String":
|
||||
defaultReturnValue = Expression.Constant(null, typeof(string));
|
||||
break;
|
||||
case "Int32":
|
||||
defaultReturnValue = Expression.Constant(0, typeof(int));
|
||||
break;
|
||||
case "Boolean":
|
||||
defaultReturnValue = Expression.Constant(false, typeof(bool));
|
||||
break;
|
||||
}
|
||||
|
||||
var defaultReturnValue = Expression.Constant(methodReturnType.GetDefaultValue(), methodReturnType);
|
||||
|
||||
ParameterExpression result = Expression.Parameter(method.ReturnType, "result");
|
||||
LabelTarget blockReturnLabel = Expression.Label(method.ReturnType);
|
||||
BlockExpression block = Expression.Block(
|
||||
@@ -1050,16 +1060,24 @@ namespace Umbraco.Web.Dynamics
|
||||
Expression.Label(blockReturnLabel, defaultReturnValue)
|
||||
);
|
||||
|
||||
switch (methodReturnType.Name)
|
||||
{
|
||||
case "String":
|
||||
return Expression.Lambda<Func<T, string>>(block, instanceExpression);
|
||||
case "Int32":
|
||||
return Expression.Lambda<Func<T, int>>(block, instanceExpression);
|
||||
case "Boolean":
|
||||
return Expression.Lambda<Func<T, bool>>(block, instanceExpression);
|
||||
}
|
||||
return Expression.Call(instance, (MethodInfo)method, args);
|
||||
Type func = typeof(Func<,>);
|
||||
Type generic = func.MakeGenericType(typeof(T), methodReturnType);
|
||||
return Expression.Lambda(generic, block, instanceExpression);
|
||||
|
||||
//if (methodReturnType == typeof(string))
|
||||
// return Expression.Lambda<Func<T, string>>(block, instanceExpression);
|
||||
//if (methodReturnType == typeof(int))
|
||||
// return Expression.Lambda<Func<T, int>>(block, instanceExpression);
|
||||
//if (methodReturnType == typeof(bool))
|
||||
// return Expression.Lambda<Func<T, bool>>(block, instanceExpression);
|
||||
//if (methodReturnType == typeof(string[]))
|
||||
//return Expression.Lambda<Func<T, string[]>>(block, instanceExpression);
|
||||
|
||||
//return Expression.Call(instance, (MethodInfo)method, args);
|
||||
|
||||
//return Expression.Lambda<Func<T, object>>(
|
||||
// Expression.Convert(block, typeof(object)), instanceExpression);
|
||||
|
||||
}
|
||||
|
||||
static Type FindGenericType(Type generic, Type type)
|
||||
@@ -1398,7 +1416,23 @@ namespace Umbraco.Web.Dynamics
|
||||
{
|
||||
ParameterInfo pi = method.Parameters[i];
|
||||
if (pi.IsOut) return false;
|
||||
Expression promoted = PromoteExpression(args[i], pi.ParameterType, false);
|
||||
Expression promoted;
|
||||
|
||||
//TODO: Turns out this is real difficult to parse and don't really have time to figure this out at the moment
|
||||
// to parse params parameter arrays.
|
||||
|
||||
////here we need to check if it is a params array parameter
|
||||
//if (pi.ParameterType.IsArray
|
||||
// && pi.ParameterType.GetElementType() != null
|
||||
// && pi.GetCustomAttributes(typeof(ParamArrayAttribute), false).Any())
|
||||
//{
|
||||
// //it is a params parameter so convert the value to an array
|
||||
// promoted = PromoteExpression(args[i], pi.ParameterType.GetElementType(), false);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
promoted = PromoteExpression(args[i], pi.ParameterType, false);
|
||||
//}
|
||||
if (promoted == null) return false;
|
||||
promotedArgs[i] = promoted;
|
||||
}
|
||||
|
||||
@@ -8,11 +8,9 @@ namespace System.Linq.Dynamic
|
||||
[Obsolete("This class has been superceded by Umbraco.Core.Dynamics.DynamicExpression")]
|
||||
public static class DynamicExpression
|
||||
{
|
||||
public static bool ConvertDynamicNullToBooleanFalse
|
||||
{
|
||||
get { return Umbraco.Web.Dynamics.DynamicExpression.ConvertDynamicNullToBooleanFalse; }
|
||||
set { Umbraco.Web.Dynamics.DynamicExpression.ConvertDynamicNullToBooleanFalse = value; }
|
||||
}
|
||||
[Obsolete("This property is no longer used and had caused concurrency issues.")]
|
||||
public static bool ConvertDynamicNullToBooleanFalse { get; set; }
|
||||
|
||||
public static Expression Parse(Type resultType, string expression, bool convertDynamicNullToBooleanFalse, params object[] values)
|
||||
{
|
||||
return Umbraco.Web.Dynamics.DynamicExpression.Parse<DynamicNode>(resultType, expression, convertDynamicNullToBooleanFalse, values);
|
||||
|
||||
@@ -9,8 +9,8 @@ namespace System.Linq.Dynamic
|
||||
[Obsolete("This class is no longer used, use Umbraco.Web.Dynamics.ExpressionParser<T> instead")]
|
||||
internal class ExpressionParser : Umbraco.Web.Dynamics.ExpressionParser<DynamicNode>
|
||||
{
|
||||
public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values)
|
||||
: base(parameters, expression, values)
|
||||
public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values, bool flagConvertDynamicNullToBooleanFalse)
|
||||
: base(parameters, expression, values, flagConvertDynamicNullToBooleanFalse)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user