maui-linux/Xamarin.Forms.Platform.UAP/WindowsExpressionSearch.cs

165 строки
4.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Xamarin.Forms.Internals;
namespace Xamarin.Forms.Platform.UWP
{
internal sealed class WindowsExpressionSearch : IExpressionSearch
{
List<object> _results;
Type _targeType;
public List<T> FindObjects<T>(Expression expression) where T : class
{
_results = new List<object>();
_targeType = typeof(T);
Visit(expression);
List<T> final = _results.Cast<T>().ToList();
_results = null;
return final;
}
void Visit(Expression expression)
{
if (expression == null)
return;
switch (expression.NodeType)
{
case ExpressionType.Negate:
case ExpressionType.NegateChecked:
case ExpressionType.Not:
case ExpressionType.Convert:
case ExpressionType.ConvertChecked:
case ExpressionType.ArrayLength:
case ExpressionType.Quote:
case ExpressionType.TypeAs:
case ExpressionType.UnaryPlus:
Visit(((UnaryExpression)expression).Operand);
break;
case ExpressionType.Add:
case ExpressionType.AddChecked:
case ExpressionType.Subtract:
case ExpressionType.SubtractChecked:
case ExpressionType.Multiply:
case ExpressionType.MultiplyChecked:
case ExpressionType.Divide:
case ExpressionType.Modulo:
case ExpressionType.Power:
case ExpressionType.And:
case ExpressionType.AndAlso:
case ExpressionType.Or:
case ExpressionType.OrElse:
case ExpressionType.LessThan:
case ExpressionType.LessThanOrEqual:
case ExpressionType.GreaterThan:
case ExpressionType.GreaterThanOrEqual:
case ExpressionType.Equal:
case ExpressionType.NotEqual:
case ExpressionType.Coalesce:
case ExpressionType.ArrayIndex:
case ExpressionType.RightShift:
case ExpressionType.LeftShift:
case ExpressionType.ExclusiveOr:
var binary = (BinaryExpression)expression;
Visit(binary.Left);
Visit(binary.Right);
Visit(binary.Conversion);
break;
case ExpressionType.TypeIs:
Visit(((TypeBinaryExpression)expression).Expression);
break;
case ExpressionType.Conditional:
var conditional = (ConditionalExpression)expression;
Visit(conditional.Test);
Visit(conditional.IfTrue);
Visit(conditional.IfFalse);
break;
case ExpressionType.MemberAccess:
VisitMemberAccess((MemberExpression)expression);
break;
case ExpressionType.Call:
var methodCall = (MethodCallExpression)expression;
Visit(methodCall.Object);
VisitList(methodCall.Arguments, Visit);
break;
case ExpressionType.Lambda:
Visit(((LambdaExpression)expression).Body);
break;
case ExpressionType.New:
VisitList(((NewExpression)expression).Arguments, Visit);
break;
case ExpressionType.NewArrayInit:
case ExpressionType.NewArrayBounds:
VisitList(((NewArrayExpression)expression).Expressions, Visit);
break;
case ExpressionType.Invoke:
var invocation = (InvocationExpression)expression;
VisitList(invocation.Arguments, Visit);
Visit(invocation.Expression);
break;
case ExpressionType.MemberInit:
var init = (MemberInitExpression)expression;
VisitList(init.NewExpression.Arguments, Visit);
VisitList(init.Bindings, VisitBinding);
break;
case ExpressionType.ListInit:
var init1 = (ListInitExpression)expression;
VisitList(init1.NewExpression.Arguments, Visit);
VisitList(init1.Initializers, initializer => VisitList(initializer.Arguments, Visit));
break;
case ExpressionType.Constant:
break;
default:
throw new ArgumentException(string.Format("Unhandled expression type: '{0}'", expression.NodeType));
}
}
void VisitBinding(MemberBinding binding)
{
switch (binding.BindingType)
{
case MemberBindingType.Assignment:
Visit(((MemberAssignment)binding).Expression);
break;
case MemberBindingType.MemberBinding:
VisitList(((MemberMemberBinding)binding).Bindings, VisitBinding);
break;
case MemberBindingType.ListBinding:
VisitList(((MemberListBinding)binding).Initializers, initializer => VisitList(initializer.Arguments, Visit));
break;
default:
throw new ArgumentException(string.Format("Unhandled binding type '{0}'", binding.BindingType));
}
}
static void VisitList<TList>(IEnumerable<TList> list, Action<TList> visitor)
{
foreach (TList element in list)
{
visitor(element);
}
}
// All important magic happens here
void VisitMemberAccess(MemberExpression member)
{
if (member.Expression is ConstantExpression && member.Member is FieldInfo)
{
object container = ((ConstantExpression)member.Expression).Value;
object value = ((FieldInfo)member.Member).GetValue(container);
if (ReflectionExtensions.IsInstanceOfType(_targeType, value))
{
_results.Add(value);
}
}
Visit(member.Expression);
}
}
}