2011-02-07 47 views
15

Tôi đang cố gắng tạo một phương thức bằng cách sử dụng cây biểu thức trả về một đối tượng, nhưng tôi không thể tìm ra cách thực sự chỉ định đối tượng cần trả về. Tôi đã thử đọc this, nhưng giá trị trả lại dường như không được chỉ định ở bất kỳ đâu.Làm cách nào để chỉ định đối tượng trả về từ phương thức cây biểu thức?

Tôi có tất cả các bài tập & công cụ xuống, nhưng làm cách nào để chỉ định đối tượng trả về từ phương thức được tạo bằng cách sử dụng cây biểu thức?

EDIT: đây là những cây biểu v4, và phương pháp Tôi đang cố gắng để tạo ra điều gì đó như thế này:

private object ReadStruct(BinaryReader reader) { 
    StructType obj = new StructType(); 
    obj.Field1 = reader.ReadSomething(); 
    obj.Field2 = reader.ReadSomething(); 
    //...more... 
    return obj; 
} 
+0

Vì điều này thực sự tạo nên sự khác biệt, đó là các cây biểu thức v3 hoặc v4? Ngoài ra, bạn có thể hiển thị ví dụ về mã mà bạn đang cố gắng trình bày với cây không? –

+0

cây biểu hiện v4. Đã chỉnh sửa để thêm mã. – thecoop

Trả lời

18

Rõ ràng một return là một GotoExpression mà bạn có thể tạo ra bằng phương pháp Expression.Return nhà máy. Bạn cần phải tạo một nhãn ở cuối để nhảy đến nó. Một cái gì đó như thế này:

// an expression representing the obj variable 
ParameterExpression objExpression = ...; 

LabelTarget returnTarget = Expression.Label(typeof(StructType)); 

GotoExpression returnExpression = Expression.Return(returnTarget, 
    objExpression, typeof(StructType)); 

LabelExpression returnLabel = Expression.Label(returnTarget, defaultValue); 

BlockExpression block = Expression.Block(
    /* ... variables, all the other lines and... */, 
    returnExpression, 
    returnLabel); 

Loại mục tiêu nhãn và biểu thức goto phải khớp. Vì mục tiêu nhãn có một loại, biểu thức nhãn phải có giá trị mặc định.

+1

Đối số 'nhãn' trỏ đến đâu? – thecoop

+2

@thecoop: phải thay đổi một số thứ khác, nhưng tôi đã làm việc đó. Chết tiệt điều này chắc chắn là rất nhiều rắc rối để có được làm việc! –

+2

Ay, nó hoạt động. Bất kỳ ý tưởng tại sao nó rất phức tạp? – thecoop

11

Tôi đã tìm thấy một vài nguồn ngụ ý (một trường hợp) hoặc thực sự là một trường hợp khác trả về giá trị từ biểu thức có thể được thực hiện đơn giản bằng cách kết thúc khối với biểu thức tham số tương ứng với giá trị được đề cập , vì biểu thức có giá trị cuối cùng từ một khối trở thành giá trị trả về của nó. Được biết, nhà máy Expression.Return tồn tại đối với các trường hợp phức tạp hơn trong đó có một trường hợp trả về từ giữa một khối mã.

Nói cách khác, nếu biểu thức cuối cùng bên trong khối của bạn đơn giản là objExpression, điều đó là đủ. Tôi nghĩ, nếu bạn deconstruct tất cả các doanh nghiệp với phương pháp Return và nhãn, rằng những gì thực sự xảy ra là objExpression về cơ bản là giao cho nhãn (ở cuối khối) và còn lại ở đó, nhiều như sẽ xảy ra nếu bạn loại bỏ returnExpression và returnLabel và chỉ cần kết luận với objExpression.

Thật không may, tôi không ở vị trí thực sự để tự mình kiểm tra.

+4

Xác minh trong .NET 4.5 – bugventure

+0

làm việc cho tôi trong .NET 4. thậm chí chỉ 'Expression.Constant (null)' ở cuối biểu thức khối để trả về null. –

22

Có một cách dễ dàng hơn để thực hiện việc này trong trường hợp trả lại tham số hoặc biến hiện tại. Câu lệnh cuối cùng trong một biểu thức khối trở thành giá trị trả về. Bạn có thể bao gồm ParameterExpression một lần nữa ở cuối để nó được trả về.

Giả sử struct của bạn là như thế này:

public struct StructType 
{ 
    public byte Field1; 
    public short Field2; 
} 

Sau đó, mã của bạn sẽ trông như thế này:

var readerType = typeof(BinaryReader); 
var structType = typeof(StructType); 
var readerParam = Expression.Parameter(readerType); 
var structVar = Expression.Variable(structType); 

var expressions = new List<Expression>(); 

expressions.Add(
    Expression.Assign(
     Expression.MakeMemberAccess(structVar, structType.GetField("Field1")), 
     Expression.Call(readerParam, readerType.GetMethod("ReadByte")) 
     ) 
    ); 

expressions.Add(
    Expression.Assign(
     Expression.MakeMemberAccess(structVar, structType.GetField("Field2")), 
     Expression.Call(readerParam, readerType.GetMethod("ReadInt16")) 
     ) 
    ); 

expressions.Add(structVar); //This is the key. This will be the return value. 

var ReadStruct = Expression.Lambda<Func<BinaryReader, StructType>>(
    Expression.Block(new[] {structVar}, expressions), 
    readerParam).Compile(); 

Kiểm tra rằng nó hoạt động:

var stream = new MemoryStream(new byte[] {0x57, 0x46, 0x07}); 
var reader = new BinaryReader(stream); 
var struct1 = ReadStruct(reader); 

Nó đáng nói ví dụ này hoạt động nếu StructType là một cấu trúc. Nếu nó là một lớp, bạn chỉ cần gọi hàm khởi tạo và khởi tạo structVar điều đầu tiên trong BlockExpression.

Các vấn đề liên quan