44
55public class DirectParameterMemberFinder : ExpressionVisitor
66{
7+ private readonly bool _expression ;
8+
79 private readonly Stack < bool > _isInsideParameterChain = new ( ) ;
810 private readonly HashSet < Expression > _TargetParams ;
911 public List < Expression > FoundMembers { get ; } = new ( ) ;
1012
11-
1213 public DirectParameterMemberFinder ( params Expression [ ] targetParams )
1314 {
1415 _TargetParams = new HashSet < Expression > ( targetParams ) ;
1516 }
1617
17- protected override Expression VisitParameter ( ParameterExpression node )
18- {
19- _isInsideParameterChain . Push ( true ) ;
20- var result = base . VisitParameter ( node ) ;
21- _isInsideParameterChain . Pop ( ) ;
22- return result ;
23- }
18+
2419
2520 protected override Expression VisitMember ( MemberExpression node )
2621 {
27- if ( node . Expression is ParameterExpression || _isInsideParameterChain . Any ( x => x ) )
28- {
29- FoundMembers . Add ( node ) ;
30- }
22+ var getParam = new GetParametr ( ) ;
3123
32- _isInsideParameterChain . Push ( _isInsideParameterChain . Any ( x => x ) ) ;
33- this . Visit ( node . Expression ) ;
34- _isInsideParameterChain . Pop ( ) ;
35- return node ;
36- }
24+ var param = getParam . GetParam ( node . Expression ) ;
3725
38- protected override Expression VisitIndex ( IndexExpression node )
39- {
40- if ( _isInsideParameterChain . Any ( x => x ) )
41- {
26+ if ( _TargetParams . Contains ( param ) )
4227 FoundMembers . Add ( node ) ;
43- }
4428
45- _isInsideParameterChain . Push ( _isInsideParameterChain . Any ( x => x ) ) ;
46- this . Visit ( node . Object ) ;
47- foreach ( var argument in node . Arguments )
48- {
49- this . Visit ( argument ) ;
50- }
51- _isInsideParameterChain . Pop ( ) ;
5229 return node ;
30+
5331 }
5432
33+
34+
5535 protected override Expression VisitUnary ( UnaryExpression node )
5636 {
5737 if ( node . NodeType == ExpressionType . Convert || node . NodeType == ExpressionType . ConvertChecked )
5838 {
59- _isInsideParameterChain . Push ( _isInsideParameterChain . Any ( x => x ) ) ;
39+ bool parentWasInChain = _isInsideParameterChain . Any ( x => x ) ;
40+ _isInsideParameterChain . Push ( parentWasInChain ) ;
6041 var result = base . VisitUnary ( node ) ;
6142 _isInsideParameterChain . Pop ( ) ;
6243 return result ;
6344 }
6445 return base . VisitUnary ( node ) ;
6546 }
66-
67- protected override Expression VisitBinary ( BinaryExpression node )
47+
48+ public IEnumerable < Expression > Find ( Expression expression )
6849 {
69- this . Visit ( node . Left ) ;
70- this . Visit ( node . Right ) ;
71- return node ;
50+ FoundMembers . Clear ( ) ;
51+ Visit ( expression ) ;
52+
53+ // Теперь фильтрация проще: благодаря правильному порядку обхода в VisitMember,
54+ // в список попадают только те члены, которые висят над параметром.
55+ return FoundMembers ;
7256 }
57+ }
58+
7359
74- protected override Expression VisitMethodCall ( MethodCallExpression node )
60+
61+ public class GetParametr : ExpressionVisitor
62+ {
63+ private Expression parametr ;
64+
65+ protected override Expression VisitParameter ( ParameterExpression node )
7566 {
76- if ( node . Object != null )
77- {
78- this . Visit ( node . Object ) ;
79- }
80- foreach ( var arg in node . Arguments )
81- {
82- this . Visit ( arg ) ;
83- }
67+
68+ parametr = node ;
69+
8470 return node ;
8571 }
8672
87- public IEnumerable < Expression > Find ( Expression expression )
73+ public Expression GetParam ( Expression expression )
8874 {
89- FoundMembers . Clear ( ) ;
9075 Visit ( expression ) ;
91- return FoundMembers
92- . Where ( m =>
93- {
94- var current = m ;
95-
96- // Поднимаемся вверх по дереву выражения до самого корня этого MemberAccess
97- while ( current != null )
98- {
99- if ( current is ParameterExpression p && _TargetParams . Contains ( p ) )
100- {
101- return true ; // Нашли целевой параметр в цепочке
102- }
103-
104- if ( current is MemberExpression nextMember )
105- {
106- current = nextMember . Expression ;
107- }
108- else if ( current is UnaryExpression unary &&
109- ( unary . NodeType == ExpressionType . Convert || unary . NodeType == ExpressionType . ConvertChecked ) )
110- {
111- current = unary . Operand ;
112- }
113- else
114- {
115- break ;
116- }
117- }
118- return false ;
119- } ) ;
120- }
76+
77+ return parametr ;
78+ }
12179}
0 commit comments