|
@@ -5,127 +5,166 @@ using System.Linq;
|
|
|
using System.Linq.Expressions;
|
|
|
|
|
|
using Vit.Linq.ExpressionTree.ComponentModel;
|
|
|
+using Vit.Linq.ExpressionTree.ExpressionConvertor;
|
|
|
|
|
|
namespace Vit.Linq.ExpressionTree
|
|
|
{
|
|
|
-
|
|
|
+ public enum EValueType
|
|
|
+ {
|
|
|
+ /// <summary>
|
|
|
+ /// constant value like 1.5 or int[]{1,2,3}
|
|
|
+ /// </summary>
|
|
|
+ constant,
|
|
|
+ /// <summary>
|
|
|
+ /// QueryableArgument
|
|
|
+ /// </summary>
|
|
|
+ argument,
|
|
|
+ /// <summary>
|
|
|
+ /// like parameter from lambda argument or combined value
|
|
|
+ /// </summary>
|
|
|
+ other,
|
|
|
+ }
|
|
|
public class DataConvertArgument
|
|
|
{
|
|
|
public bool autoReduce { get; set; } = false;
|
|
|
|
|
|
+ public Func<ConstantExpression, bool> isArgument { get; set; }
|
|
|
|
|
|
- public bool ReduceValue<T>(Expression expression, out T value)
|
|
|
+ public virtual bool IsArgument(ConstantExpression constant)
|
|
|
{
|
|
|
- try
|
|
|
- {
|
|
|
- if (autoReduce && CanCalculateToConstant(expression))
|
|
|
- {
|
|
|
- value = (T)InvokeExpression(expression);
|
|
|
- return true;
|
|
|
- }
|
|
|
- }
|
|
|
- catch (Exception ex)
|
|
|
+ if (isArgument != null)
|
|
|
+ return isArgument(constant);
|
|
|
+
|
|
|
+ var type = constant.Type;
|
|
|
+ //var value = constant.Value;
|
|
|
+ if (!type.IsArray && type.IsGenericType && typeof(IQueryable).IsAssignableFrom(type))
|
|
|
{
|
|
|
+ //if (typeof(List<>) == type.GetGenericTypeDefinition())
|
|
|
+ // return false;
|
|
|
+
|
|
|
+ return true;
|
|
|
}
|
|
|
- value = default;
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
- public static object InvokeExpression(Expression expression)
|
|
|
- {
|
|
|
- return Expression.Lambda(expression).Compile().DynamicInvoke();
|
|
|
- }
|
|
|
-
|
|
|
- public static bool CanCalculateToConstant(Expression expression)
|
|
|
+ /// <summary>
|
|
|
+ /// TODO: use object hashcode to cache EValueType
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="expression"></param>
|
|
|
+ /// <returns></returns>
|
|
|
+ protected EValueType GetEValueType(Expression expression)
|
|
|
{
|
|
|
+ List<EValueType> childrenTypes;
|
|
|
switch (expression)
|
|
|
{
|
|
|
- case null: return true;
|
|
|
+ case null: return EValueType.constant;
|
|
|
+
|
|
|
+ case ConstantExpression constant:
|
|
|
+ {
|
|
|
+ if (IsArgument(constant)) return EValueType.argument;
|
|
|
+ return EValueType.constant;
|
|
|
+ }
|
|
|
case MemberExpression member:
|
|
|
{
|
|
|
- return CanCalculateToConstant(member.Expression);
|
|
|
+ return GetEValueType(member.Expression);
|
|
|
}
|
|
|
case UnaryExpression unary:
|
|
|
{
|
|
|
- //switch (unary.NodeType)
|
|
|
- //{
|
|
|
- // case ExpressionType.Convert:
|
|
|
- // case ExpressionType.Quote:
|
|
|
- // return CouldExecuteToConst(unary.Operand);
|
|
|
- //}
|
|
|
- return CanCalculateToConstant(unary.Operand);
|
|
|
+ return GetEValueType(unary.Operand) == EValueType.constant ? EValueType.constant : EValueType.other;
|
|
|
}
|
|
|
case BinaryExpression binary:
|
|
|
{
|
|
|
- return CanCalculateToConstant(binary.Left)&& CanCalculateToConstant(binary.Right);
|
|
|
- }
|
|
|
- case ConstantExpression constant:
|
|
|
- {
|
|
|
- var type = expression.Type;
|
|
|
- var value = constant.Value;
|
|
|
- if (value == null) return true;
|
|
|
- if (IsQueryableArgument(type)) return false;
|
|
|
- return true;
|
|
|
+ childrenTypes = new List<EValueType> { GetEValueType(binary.Left), GetEValueType(binary.Right) };
|
|
|
+ break;
|
|
|
}
|
|
|
case NewArrayExpression newArray:
|
|
|
{
|
|
|
- return newArray.Expressions?.All(exp => CanCalculateToConstant(exp)) != false;
|
|
|
+ childrenTypes = newArray.Expressions?.Select(GetEValueType).ToList();
|
|
|
+ break;
|
|
|
}
|
|
|
case ListInitExpression listInit:
|
|
|
{
|
|
|
- return listInit.Initializers?.All(exp => CanCalculateToConstant(exp.Arguments[0])) != false;
|
|
|
+ childrenTypes = listInit.Initializers?.Select(exp => GetEValueType(exp.Arguments[0])).ToList();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case MethodCallExpression call:
|
|
|
+ {
|
|
|
+ childrenTypes = new();
|
|
|
+ if (call.Arguments?.Any() == true) childrenTypes.AddRange(call.Arguments.Select(GetEValueType));
|
|
|
+ if (call.Object != null) childrenTypes.Add(GetEValueType(call.Object));
|
|
|
+ break;
|
|
|
}
|
|
|
+ default: return EValueType.other;
|
|
|
}
|
|
|
- return false;
|
|
|
+ if (childrenTypes?.Any() != true) return EValueType.constant;
|
|
|
+
|
|
|
+ if (childrenTypes.All(m => m == EValueType.constant)) return EValueType.constant;
|
|
|
+ return EValueType.other;
|
|
|
}
|
|
|
|
|
|
- #region Type
|
|
|
|
|
|
- public static bool IsQueryableArgument(Type type)
|
|
|
+ public bool ReduceValue<T>(Expression expression, out T value)
|
|
|
{
|
|
|
- if (!type.IsArray && type.IsGenericType && typeof(IQueryable).IsAssignableFrom(type))
|
|
|
+ try
|
|
|
{
|
|
|
- //if (typeof(List<>) == type.GetGenericTypeDefinition())
|
|
|
- // return false;
|
|
|
-
|
|
|
- return true;
|
|
|
+ if (autoReduce && CanCalculateToConstant(expression))
|
|
|
+ {
|
|
|
+ value = (T)InvokeExpression(expression);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ }
|
|
|
+ value = default;
|
|
|
return false;
|
|
|
+ }
|
|
|
|
|
|
+ public static object InvokeExpression(Expression expression)
|
|
|
+ {
|
|
|
+ return Expression.Lambda(expression).Compile().DynamicInvoke();
|
|
|
}
|
|
|
- public static bool IsTransportableType(Type type)
|
|
|
+
|
|
|
+ public bool CanCalculateToConstant(Expression expression)
|
|
|
{
|
|
|
- if (IsBasicType(type)) return true;
|
|
|
+ return GetEValueType(expression) == EValueType.constant;
|
|
|
+ }
|
|
|
|
|
|
- if (type.IsArray && IsTransportableType(type.GetElementType()))
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
+ #region Type
|
|
|
|
|
|
- if (type.IsGenericType)
|
|
|
- {
|
|
|
- if (type.GetGenericArguments().Any(t => !IsTransportableType(t))) return false;
|
|
|
|
|
|
- if (typeof(IList).IsAssignableFrom(type)
|
|
|
- || typeof(ICollection).IsAssignableFrom(type)
|
|
|
- )
|
|
|
- return true;
|
|
|
- }
|
|
|
+ //public static bool IsTransportableType(Type type)
|
|
|
+ //{
|
|
|
+ // if (IsBasicType(type)) return true;
|
|
|
|
|
|
- return false;
|
|
|
- }
|
|
|
+ // if (type.IsArray && IsTransportableType(type.GetElementType()))
|
|
|
+ // {
|
|
|
+ // return true;
|
|
|
+ // }
|
|
|
|
|
|
+ // if (type.IsGenericType)
|
|
|
+ // {
|
|
|
+ // if (type.GetGenericArguments().Any(t => !IsTransportableType(t))) return false;
|
|
|
|
|
|
- // is valueType of Nullable
|
|
|
- public static bool IsBasicType(Type type)
|
|
|
- {
|
|
|
- return
|
|
|
- type.IsEnum || // enum
|
|
|
- type == typeof(string) || // string
|
|
|
- type.IsValueType || //int
|
|
|
- (type.IsGenericType && typeof(Nullable<>) == type.GetGenericTypeDefinition()); // int?
|
|
|
- }
|
|
|
+ // if (typeof(IList).IsAssignableFrom(type)
|
|
|
+ // || typeof(ICollection).IsAssignableFrom(type)
|
|
|
+ // )
|
|
|
+ // return true;
|
|
|
+ // }
|
|
|
+
|
|
|
+ // return false;
|
|
|
+ //}
|
|
|
+
|
|
|
+
|
|
|
+ //// is valueType of Nullable
|
|
|
+ //public static bool IsBasicType(Type type)
|
|
|
+ //{
|
|
|
+ // return
|
|
|
+ // type.IsEnum || // enum
|
|
|
+ // type == typeof(string) || // string
|
|
|
+ // type.IsValueType || //int
|
|
|
+ // (type.IsGenericType && typeof(Nullable<>) == type.GetGenericTypeDefinition()); // int?
|
|
|
+ //}
|
|
|
|
|
|
|
|
|
#endregion
|
|
@@ -190,7 +229,7 @@ namespace Vit.Linq.ExpressionTree
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
+
|
|
|
}
|
|
|
|
|
|
|