Tôi có một phương pháp tĩnh:Delegate.CreateDelegate sẽ không đưa ra giá trị trả về - cố tình, hoặc không hoạt động?
public class Example
{
//for demonstration purposes - just returns default(T)
public static T Foo<T>() { return default(T); }
}
Và tôi cần để có thể gọi nó bằng một tham số Type
cuộc gọi đến mà có thể là nhiều, vì vậy mô hình tiêu chuẩn của tôi là tạo ra một bộ nhớ cache thread-safe của các đại biểu (sử dụng ConcurrentDictionary
trong .Net 4) tự động gọi phương thức Foo<T>
với chính xác T
. Nếu không có bộ nhớ đệm, tuy nhiên, mã này là:
static object LateFoo(Type t)
{
//creates the delegate and invokes it in one go
return (Func<object>)Delegate.CreateDelegate(
typeof(Func<object>),
typeof(Example).GetMethod("Foo", BindingFlags.Public | BindingFlags.Static).
MakeGenericMethod(t))();
}
Đây không phải là lần đầu tiên tôi đã phải làm điều này - và trong quá khứ tôi đã sử dụng cây biểu thức để xây dựng và biên soạn một proxy để gọi phương pháp đích - để đảm bảo rằng việc chuyển đổi kiểu trả về và boxing từ đối tượng int -> (ví dụ) được xử lý một cách chính xác.
Update - ví dụ về mã biểu làm việc
static object LateFoo(Type t)
{
var method = typeof(Example)
.GetMethod("Foo", BindingFlags.Public | BindingFlags.Static)
.MakeGenericMethod(t);
//in practise I cache the delegate, invoking it freshly built or from the cache
return Expression.Lambda<Func<IField, object>>(Expression.Convert(
Expression.Call(method), typeof(object))).Compile()();
}
gì hơi buồn cười là tôi học được từ rất sớm với các biểu thức rằng một rõ ràng Convert
được yêu cầu và chấp nhận nó - và thay cho câu trả lời ở đây nó bây giờ không có ý nghĩa tại sao khuôn khổ Net không tự động gắn bó tương đương trong.
End cập nhật
Tuy nhiên, lần này tôi nghĩ tôi chỉ muốn sử dụng Delegate.CreateDelegate
vì nó làm cho tấn công tuyệt vời của thực tế là (từ MSDN):
Tương tự, kiểu trả về của một đại biểu là phù hợp với kiểu trả về của một phương thức nếu kiểu trả về của phương thức là hạn chế hơn kiểu trả về của đại biểu, bởi vì điều này đảm bảo rằng giá trị trả về của phương thức có thể được truyền an toàn đến kiểu trả về của đại biểu.
Bây giờ - nếu tôi vượt qua typeof(string)
đến LateFoo
, mọi thứ đều ổn.
Nếu, tuy nhiên, tôi vượt qua typeof(int)
Tôi nhận được ArgumentException
trên số CreateDelegate
cuộc gọi, tin nhắn: Error binding to target method
. Không có ngoại lệ bên trong hoặc thông tin thêm.
Vì vậy, có vẻ như, đối với mục đích ràng buộc phương pháp, object
không được coi là hạn chế hơn int
. Rõ ràng, điều này phải được thực hiện với boxing là một hoạt động khác với một loại chuyển đổi đơn giản và các loại giá trị không được coi là covariant thành object
trong khuôn khổ .Net; mặc dù mối quan hệ kiểu thực tế khi chạy.
Các biên dịch C# dường như đồng ý với điều này (chỉ con đường ngắn nhất tôi có thể mô hình lỗi, bỏ qua những gì mã sẽ làm gì):
public static int Foo()
{
Func<object> f = new Func<object>(Foo);
return 0;
}
Không biên dịch bởi vì phương pháp Foo
'có kiểu trả về sai '- đưa ra các vấn đề CreateDelegate
, C# chỉ đơn giản là sau.
Dường như với tôi điều đó.Net là không phù hợp trong điều trị hiệp phương sai - hoặc là một loại giá trị là object
hoặc không; & nếu không, không được để lộ object
làm cơ sở (mặc dù nó sẽ khó khăn hơn bao nhiêu trong cuộc sống của chúng ta). Vì nó phơi bày object
làm cơ sở (hoặc là nó chỉ là ngôn ngữ thực hiện điều đó?), Sau đó theo logic một loại giá trị nên được so sánh với object
(hoặc bất kỳ cách nào xung quanh bạn có nghĩa vụ phải nói nó) làm cho ràng buộc đại biểu này đúng. Nếu hiệp phương sai đó chỉ có thể đạt được thông qua một hoạt động đấm bốc; thì khung công tác phải quan tâm đến điều đó.
Tôi dám nói câu trả lời ở đây sẽ là CreateDelegate không nói rằng nó sẽ xử lý một hoạt động hộp trong hiệp phương sai vì nó chỉ sử dụng từ 'đúc'. Tôi cũng hy vọng có toàn bộ luận thuyết về chủ đề rộng hơn về các loại giá trị và hiệp phương sai đối tượng, và tôi đang hét lên về một chủ đề lâu dài và không còn tồn tại. Tôi nghĩ rằng có điều gì đó mà tôi không hiểu hoặc đã bỏ lỡ, mặc dù - vì vậy hãy khai sáng!
Nếu điều này là không thể trả lời - Tôi rất sẵn lòng xóa.
@ HenkHolterman: Tôi nghĩ vậy, nhưng vẫn tiếp tục đọc và tôi nghĩ đó là một câu hỏi hay. –
Tôi phải thiếu thứ gì đó vì tôi không thể biên dịch phương thức MakeDelegate 'Không thể chuyển đổi System.Delegate thành Func
@ Myles - bạn nói đúng - bỏ lỡ một diễn viên ... xin lỗi –