Dưới đây là một mã trình diễn đơn giản về vấn đề của tôi.Nhận ConstantExpression.Value khi giá trị thực tế được đưa vào DisplayClass do đóng
[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
phương pháp gây VisitConstant
được gọi trên hai con đường khác nhau:
1.TestParam
->Search
->VisitConstant
Trong con đường thực hiện này biểu hiện liên tục (1L) truyền cho Search
là một giá trị hằng số thực. Ở đây, mọi thứ đều ổn, khẳng định thành công như mong đợi. Khi VisitConstant
được gọi qua đường dẫn đầu tiên node.Value.GetType()
là Int64
và .Value
là 1L
.
2.TestParam
->GetStudent
->Search
->VisitConstant
Trong cụm từ này con đường thực hiện liên tục (id: 1L), được thực hiện bởi GetStudent
như một tham số và truyền cho Search
phương pháp bên trong một đóng cửa.
Vấn đề
Vấn đề là trên con đường thực hiện thứ hai. Khi VisitConstant
được gọi qua đường dẫn thứ hai node.Value.GetType()
là MyProject.Tests.ExpressionTests+<>c__DisplayClass0
và lớp này có trường công khai có tên là id
(giống như đối số của phương pháp GetStudent
) có giá trị là 1L
.
Câu hỏi
Làm thế nào tôi có thể nhận được id
giá trị trong con đường thứ hai? Tôi biết về đóng cửa, những gì một DisplayClass
là và tại sao nó được tạo ra tại thời gian biên dịch vv Tôi chỉ quan tâm đến việc nhận giá trị trường của nó. Một điều tôi có thể nghĩ đến là, qua sự phản chiếu. Với một cái gì đó như dưới đây nhưng nó không có vẻ gọn gàng.
node.Value.GetType().GetFields()[0].GetValue(node.Value);
Bonus Vấn đề
Trong khi chơi với các mã cho gettting id
giá trị tôi đã thay đổi VisitConstant
phương pháp như dưới đây (mà sẽ không giải quyết vấn đề của tôi mặc dù) và nhận được một ngoại lệ nói " 'đối tượng' không không chứa một định nghĩa cho 'id'"
Câu hỏi thưởng
Khi động lực được giải quyết trong thời gian chạy và DisplayClass
được tạo tại thời gian biên dịch, tại sao chúng ta không thể truy cập trường của nó bằng dynamic
? Trong khi mã bên dưới hoạt động, tôi dự kiến mã đó cũng sẽ hoạt động.
var st = new {Id = 1L};
object o = st;
dynamic dy = o;
Assert.AreEqual(1L, dy.Id);
Tốt! Đây là cách nhanh nhất để có được các giá trị cơ bản của việc đóng, đây là câu trả lời được chấp nhận. – jorgebg