2011-11-08 24 views
9

Tôi có phương thức chấp nhận cá thể Expression<Func<T, object>>. Tôi muốn truy cập vào loại dữ liệu thực tế đang được trả về bởi một cá thể biểu thức cụ thể, thay vì object.Nhận loại trả về thực tế từ Biểu thức <Func <T, object>> ví dụ

Tôi có thể làm cho nó hoạt động để tham khảo trực tiếp thuộc tính, vì vậy nếu tôi chuyển sang biểu thức x => x.IntegerProperty tôi có thể nhận tham chiếu Kiểu cho số nguyên. Cách tiếp cận này yêu cầu chuyển đổi nó thành MemberExpression.

Tuy nhiên, tôi không thể làm cho nó hoạt động cho các biểu thức tùy ý. Ví dụ, nếu biểu thức là x => x.IntegerProperty.ToString() Tôi muốn lấy tham chiếu Kiểu cho một chuỗi. Tôi không thể biên dịch nó thành MemberExpression, và nếu tôi chỉ .Compile() nó và kiểm tra kiểu trả về, tôi nhận được "đối tượng".

Làm cách nào tôi có thể xem trường hợp biểu thức cụ thể và lấy được loại trả về thực tế?

+0

Về mặt kỹ thuật, loại trả về thực tế của biểu thức là ... 'đối tượng'. Vì hàm được yêu cầu trả về 'đối tượng', các biểu thức cần thiết được tạo ra để đảm bảo rằng nó được trả về (một chuyển đổi trong trường hợp này). –

Trả lời

17

Một cái gì đó như thế này có thể làm các trick. Nó có lẽ không bao gồm mọi khả năng, nhưng đó là một sự khởi đầu.

public static Type GetObjectType<T>(Expression<Func<T, object>> expr) 
{ 
    if ((expr.Body.NodeType == ExpressionType.Convert) || 
     (expr.Body.NodeType == ExpressionType.ConvertChecked)) 
    { 
     var unary = expr.Body as UnaryExpression; 
     if (unary != null) 
      return unary.Operand.Type; 
    } 
    return expr.Body.Type; 
} 
+0

Tôi không thể nghĩ ra bất kỳ loại biểu thức nào khác có thể là nếu nó không thực sự là 'đối tượng'. Bao gồm tất cả các trường hợp mà tôi có thể nghĩ đến. –

+0

Làm việc tuyệt vời. Tôi đang sử dụng điều này trong một bộ hoàn cảnh cụ thể, vì vậy nếu có các trường hợp _are_ cạnh mà bạn chưa đề cập đến thì chúng không gây ra bất kỳ nỗi đau nào cho tôi. Cảm ơn! –

+0

Không phải là expr.Body.Type đủ? Tôi nhận được kết quả sai khi sử dụng mã ở trên với ví dụ i => (float) i trong đó i là một số nguyên. Sau đó, mã này trả về số nguyên và không nổi. Nhưng chỉ đơn giản là expr.Body.Type hoạt động. –

2

Trong khi không thể, điều này đặc biệt khó khăn. Nó sẽ yêu cầu đi bộ cây biểu hiện và thực hiện một số logic phức tạp. Ví dụ: bạn muốn xem liệu tôi có thông qua biểu thức sau đây không?

Func<bool, object> expr = switch => switch ? 1 : "False"; 

Phương pháp này có thể hoặc trả lại một int hay string.

Bây giờ, bạn có thể thực hiện nhiều tiến trình hơn bằng cách giảm tải một số logic này trên trình biên dịch. Bạn có thể thay đổi tham số phương thức của mình từ Func<T, object> thành Func<T, TReturn> và sử dụng typeof(TReturn) trong phương pháp để xác định trình biên dịch đã quyết định kiểu trả về của biểu thức là gì.

Tất nhiên, trong trường hợp của ví dụ của tôi, bạn sẽ vẫn đang làm việc với object. Tuy nhiên, ví dụ của bạn về x => x.IntegerProperty.ToString() sẽ mang lại string, đó là những gì bạn đang tìm kiếm.

+0

Bạn thực hiện một số điểm tốt, nhưng điều này đang được sử dụng trong một số trường hợp cụ thể mà các trường hợp cạnh đó không nên xuất hiện (hoặc có thể dễ dàng tránh được bằng cách biết về chúng). Cảm ơn! –

+2

Trên thực tế, @Adam Maras, ví dụ của bạn sẽ không bao giờ biên dịch vì toán tử bậc ba sẽ ném một lỗi thời gian biên dịch nói "Loại biểu thức điều kiện không thể xác định được vì không có chuyển đổi tiềm ẩn giữa 'int' và 'string'" –

+0

là một bài tập suy nghĩ nhiều hơn một mẫu mã theo nghĩa đen. –

0

Bit một cách táo bạo (và nó liên quan đến việc thực sự viện dẫn Func), nhưng bạn có thể làm điều này:

using System; 

class Program 
{ 
    static Func<T,object> MakeFunc<T>() 
    { 
     return x => 23; 
    } 

    static Type GetReturnType<T>(Func<T,object> f) 
    { 
     return f(default(T)).GetType(); 
    } 

    static void Main(string[] args) 
    { 
     Type t = GetReturnType(MakeFunc<string>()); 
     Console.WriteLine(t); 
    } 
} 

Nó không được bảo đảm để làm việc trong mọi tình huống, tôi nên thêm - đặc biệt là nếu default(T) isn không phải là thông số hợp lệ cho số Func. Nhưng đó là một điểm khởi đầu tiềm năng ít nhất.

+2

Tôi không chắc chắn làm thế nào tôi cảm thấy về việc thực hiện các biểu thức để có được kiểu trả về; nếu có phản ứng phụ với chức năng thì sao?Trong trường hợp cụ thể của tôi mà không phải là một lo lắng lớn, nhưng tôi chấp nhận một câu trả lời mà dường như làm việc chỉ là tốt và không yêu cầu thực hiện. Cảm ơn mặc dù! –

+0

@Seth: Cá nhân tôi sẽ không quá hạnh phúc về việc thực hiện biểu thức (đó là giới hạn của cách tiếp cận) - đó là điều tốt nhất tôi có thể nghĩ ra khỏi đỉnh đầu. Một ưu điểm của phương pháp này là nó hoạt động trên các cá thể 'Func' chứ không phải là các thể hiện' Expression'. –

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