Bạn có thể tạo một đại biểu của một phương thức cá thể mà không chỉ rõ cá thể tại thời gian tạo không? Nói cách khác, bạn có thể tạo ra một đại biểu "tĩnh" mà phải mất vì nó là tham số đầu tiên của cá thể phương thức nên được gọi?"Uncurrying" một phương thức thể hiện trong .NET
Ví dụ: làm thế nào tôi có thể xây dựng đại biểu sau bằng cách sử dụng sự phản chiếu?
Func<int, string> = i=>i.ToString();
Tôi biết thực tế là tôi có thể sử dụng methodInfo.Invoke, nhưng điều này chậm hơn và không kiểm tra tính chính xác của loại cho đến khi được gọi.
Khi bạn có MethodInfo
của một đặc biệt tĩnh phương pháp, chúng ta có thể xây dựng một đại biểu sử dụng Delegate.CreateDelegate(delegateType, methodInfo)
, và tất cả các thông số của phương pháp tĩnh vẫn tự do.
Như Jon Skeet đã chỉ ra, bạn có thể chỉ cần áp dụng tương tự để tạo một đại biểu mở của một phương thức thể hiện nếu phương thức không ảo trên một kiểu tham chiếu. Việc quyết định phương thức nào để gọi trên một phương thức ảo là phức tạp, vì vậy nó không có tầm quan trọng, và các kiểu giá trị trông giống như chúng không hoạt động chút nào.
Đối với các loại giá trị, CreateDelegate
triển lãm hành vi thực sự kỳ lạ:
var func37 = (Func<CultureInfo,string>)(37.ToString);
var toStringMethod = typeof(int).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public, null, new Type[] {typeof(CultureInfo) }, null);
var func42 = (Func<CultureInfo,string>)Delegate.CreateDelegate(typeof(Func<CultureInfo,string>), 42, toStringMethod,true);
Console.WriteLine(object.ReferenceEquals(func37.Method,func42.Method)); //true
Console.WriteLine(func37.Target);//37
Console.WriteLine(func42.Target);//42
Console.WriteLine(func37(CultureInfo.InvariantCulture));//37
Console.WriteLine(func42(CultureInfo.InvariantCulture));//-201040128... WTF?
Calling CreateDelegate
với null
như các đối tượng mục tiêu ném một ngoại lệ ràng buộc nếu phương pháp dụ thuộc về một kiểu giá trị (chỉ hoạt động này với nhiều loại tài liệu tham khảo).
Một vài năm theo dõi sau: Mục tiêu sai-bound khiến func42(CultureInfo.InvariantCulture);
trở "-201040128"
thay vì "42"
trong ví dụ của tôi là bộ nhớ tham nhũng mà có thể cho phép thực thi mã từ xa (cve-2010-1898); điều này đã được khắc phục vào năm 2010 trong bản cập nhật bảo mật ms10-060. Các khung hiện hành in chính xác 42! Điều đó không trả lời câu hỏi này dễ dàng hơn, nhưng giải thích hành vi đặc biệt kỳ lạ trong ví dụ.
Đây là một trong những trường hợp mà nó trở nên rõ ràng rằng C# vẫn còn chỗ để phát triển như một ngôn ngữ chức năng. Xử lý các chức năng như công dân hạng nhất vẫn không liền mạch như chúng ta có thể muốn. Có cách nào để khai thác các tính năng động trong C# 4 để làm việc này dễ dàng hơn không? – LBushkin
@LBushkin: Tôi không nghĩ vậy. Trong thực tế, gõ động và lambdas không đi quá tốt với nhau để bắt đầu - trình biên dịch phải biết loại nào để chuyển đổi biểu thức lambda thành thời gian biên dịch. –
Tôi * đã * được thử nghiệm trên int.ToString, nhưng để sử dụng thực tế tôi cho rằng tôi có thể làm mà không có các phương thức ảo - mặc dù không phải không có cấu trúc. Nhưng dù sao, cảm ơn cho người đứng đầu, tôi đã bỏ qua sự phức tạp của các phương pháp ảo, và thông báo lỗi không chính xác thông tin ... –