2009-03-28 27 views
25

Tôi đang viết .NET On-the-Fly trình biên dịch cho CLR kịch bản và muốn phương pháp thực hiện làm chung chấp nhận được:điều hành như và các lớp generic

object Execute() 
{ 
    return type.InvokeMember(..); 
} 

T Execute<T>() 
{ 
    return Execute() as T; /* doesn't work: 
    The type parameter 'T' cannot be used with the 'as' operator because 
    it does not have a class type constraint nor a 'class' constraint */ 

    // also neither typeof(T) not T.GetType(), so on are possible 

    return (T) Execute(); // ok 
} 

Nhưng tôi nghĩ rằng điều hành as sẽ rất hữu ích: nếu loại kết quả không phải là phương pháp T sẽ trả lại null, thay vì ngoại lệ! Có thể làm được không?

Trả lời

49

Bạn cần phải thêm

where T : class 

để khai phương pháp của bạn, ví dụ

T Execute<T>() where T : class 
{ 

Nhân tiện, như một đề xuất, trình bao bọc chung đó thực sự không thêm nhiều giá trị. Người gọi có thể viết:

MyClass c = whatever.Execute() as MyClass; 

Hoặc nếu họ muốn ném vào thất bại:

MyClass c = (MyClass)whatever.Execute(); 

Phương pháp wrapper chung trông như thế này:

MyClass c = whatever.Execute<MyClass>(); 

Cả ba phiên bản phải xác định chính xác cùng ba thực thể, chỉ trong các đơn đặt hàng khác nhau, vì vậy không có đơn giản hơn hoặc thuận tiện hơn, và phiên bản chung ẩn những gì đang xảy ra, trong khi các phiên bản "thô" làm cho nó rõ ràng cho dù có bị ném hoặc là null.

(Điều này có thể không liên quan đến bạn nếu ví dụ của bạn được đơn giản hóa từ mã thực tế).

+0

Cảm ơn bạn rất nhiều vì đã trả lời. Tôi sẽ sử dụng nó, kiểm tra và đánh dấu là một câu trả lời. Và, tôi đã sử dụng mã tiếp theo của tôi: MyClass c = compiler.Execute (); Tôi nghĩ rằng nó tốt hơn sau đó MyClass c = compiler.Execute() như MyClass; (kiểm tra bên trong là tốt hơn sau đó bên ngoài, tôi đoán) – abatishchev

+0

Nhưng kiểm tra vẫn còn cần thiết bên ngoài - kiểm tra cho null! :) Bằng cách làm cho người dùng viết 'như MyClass', bạn làm cho nó rõ ràng hơn rằng việc kiểm tra null là bắt buộc. –

+0

Hm .. Có vẻ như bạn đã đúng! Tôi sẽ khuyên bạn nên sử dụng 'bình thường' Thực thi(), nhưng đối với người dùng cuối nó có thể hữu ích để có 'bất thường' Execute(), ngoài ra 'thí nghiệm chung' một số cách :) – abatishchev

11

Bạn không thể sử dụng toán tử as với loại chung mà không bị giới hạn. Vì toán tử as sử dụng null để biểu thị rằng nó không thuộc loại, bạn không thể sử dụng nó trên các loại giá trị. Nếu bạn muốn sử dụng obj as T, T sẽ làm loại tham chiếu.

T Execute<T>() where T : class 
{ 
    return Execute() as T; 
} 
1

Có vẻ như bạn chỉ đang thêm phương thức trình bao bọc để truyền sang loại người dùng muốn, do đó, chỉ thêm phí vào thực thi. Đối với người dùng, viết

int result = Execute<int>(); 

là không khác nhiều so với

int result = (int)Execute(); 

Bạn có thể sử dụng ra modifier để viết kết quả vào một biến trong phạm vi của người gọi, và gửi lại một lá cờ boolean để cho biết liệu nó có thành công hay không:

bool Execute<T>(out T result) where T : class 
{ 
    result = Execute() as T; 
    return result != null; 
} 
1

Có cơ hội nào Execute() có thể trả về một loại giá trị không? Nếu có, thì bạn cần phương thức của Earwicker cho các kiểu lớp và một phương thức chung khác cho các kiểu giá trị.Có thể trông như thế này:

Nullable<T> ExecuteForValueType<T> where T : struct 

Logic bên trong phương pháp mà có thể nói

object rawResult = Execute(); 

Sau đó, bạn phải có được loại rawResult và xem nếu nó có thể được giao cho T:

Nullable<T> finalReturnValue = null; 

Type theType = rawResult.GetType(); 
Type tType = typeof(T); 

if(tType.IsAssignableFrom(theType)) 
{ 
    finalReturnValue = tType;  
} 

return finalReturnValue; 

Cuối cùng, hãy thực hiện thông báo Execute ban đầu của bạn tìm ra T nào có (loại lớp hoặc cấu trúc) và gọi triển khai thích hợp.

Lưu ý: Đây là từ bộ nhớ thô. Tôi đã làm điều này khoảng một năm trước và có lẽ không nhớ từng chi tiết. Tuy nhiên, tôi hy vọng chỉ cho bạn theo hướng chung sẽ giúp.

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