Poniżej znajduje się prosty kod demonstracyjny mojego problemu.Uzyskanie ConstantExpression.Value, gdy wartość rzeczywista owinięta w DisplayClass z powodu zamknięcia
[TestClass]
public class ExpressionTests
{
[TestMethod]
public void TestParam()
{
Search<Student>(s => s.Id == 1L);
GetStudent(1L);
}
private void GetStudent(long id)
{
Search<Student>(s => s.Id == id);
}
private void Search<T>(Expression<Func<T, bool>> filter)
{
var visitor = new MyExpressionVisitor();
visitor.Visit(filter);
}
}
public class MyExpressionVisitor : ExpressionVisitor
{
protected override Expression VisitConstant(ConstantExpression node)
{
Assert.AreEqual(1L, node.Value);
return base.VisitConstant(node);
}
}
TestParam
sposób powoduje VisitConstant
powoływać się na dwóch różnych drogach:
1.TestParam
-> ->Search
VisitConstant
przez ścieżkę wykonanie stałej ekspresji (1 L) przekazywany do Search
Metoda jest rzeczywistą stałą wartością. Tutaj wszystko jest w porządku, aserse udaje się zgodnie z oczekiwaniami. Gdy VisitConstant
jest wywoływana przez pierwszą ścieżkę i jej jest .
2.TestParam
->GetStudent
->Search
->VisitConstant
W tej ścieżce wykonanie stałej ekspresji (ID: 1 l), jest pobierana przez GetStudent
jako argumentu, i przekazywane do Search
sposób wewnątrz zamknięcia.
Problem
Problem polega na drugiej ścieżce wykonywania. Po wywołaniu VisitConstant
przez drugą ścieżkę node.Value.GetType()
jest MyProject.Tests.ExpressionTests+<>c__DisplayClass0
, a ta klasa ma publiczne pole o nazwie id
(tak samo jak argument metody) o wartości , która ma wartość 1L
.
Pytanie
Jak mogę uzyskać id
wartość w drugiej ścieżce? Wiem o zamknięciach, czym jest DisplayClass
i dlaczego jest tworzony podczas kompilacji itp. Interesuje mnie tylko uzyskanie jego wartości pola. Jedną rzeczą, o której mogę myśleć, jest refleksja. Z czymś podobnym, ale nie wydaje się zadbane.
node.Value.GetType().GetFields()[0].GetValue(node.Value);
Bonus Problem
Podczas odtwarzania z kodem dla gettting id
wartość Zmieniłem VisitConstant
sposób jak poniżej (nie rozwiąże mój problem, choć) i uzyskać wyjątek mówiąc „«przedmiot»robi nie zawierają definicji dla 'id'”
Bonus Pytanie
Jak dynamika są rozwiązywane w czasie rzeczywistym i DisplayClass
jest tworzony w czasie kompilacji, dlaczego nie mamy dostęp do jego pól z dynamic
? Podczas gdy poniższy kod działa, spodziewałem się, że kod również zadziała.
var st = new {Id = 1L};
object o = st;
dynamic dy = o;
Assert.AreEqual(1L, dy.Id);
Nice! Jest to najszybszy sposób uzyskania podstawowych wartości zamknięcia, to powinna być zaakceptowana odpowiedź. – jorgebg