2010-11-19 39 views
5

sizeof()typeof(), nhưng tại sao không phải là memberinfo() trả về một thể hiện System.Reflection.MemberInfo cho một phần mã được chọn để hỗ trợ trong mã phản chiếu.Tại sao không phải hàm phản chiếu memberinfo() cho C#

Ví dụ:

Program() 
{ 
     Type t = typeof(Foo); 

     Foo foo = new Foo(); 
     PropertyInfo pi = memberinfo(Foo.Name) as PropertyInfo; 
     // or shall it be like this 
     // PropertyInfo pi = memberinfo(foo.Name) as PropertyInfo; 

     string name = pi.GetValue(foo, null); 
} 

Tôi cố gắng để hiểu được nếu có một lý do cơ bản tại sao điều này có thể được thực hiện trong C# spec.

Tôi không bashing bất cứ điều gì, tôi chỉ làm một số suy nghĩ mơ mộng, vì vậy hãy tử tế xin vui lòng.

+0

Nó có thể có thể được triển khai dễ dàng. Tôi cũng muốn một cái gì đó như thế này Lưu ý rằng một cú pháp thay thế sẽ được yêu cầu cho các phương thức, vì chúng có thể bị quá tải, vì vậy việc chỉ định tên một mình sẽ không đủ trong trường hợp đó. – cdhowie

+0

Bạn có thể tạo một cái gì đó tương tự bằng cách sử dụng cây biểu hiện; điều này làm việc đặc biệt tốt cho các thuộc tính và các trường. –

+0

@Bryant bạn có ví dụ hoặc liên kết không? – ja72

Trả lời

8

Eric Lippert cuộc đàm phán về vấn đề này rộng rãi trên mình blog

Để trích dẫn trực tiếp từ bài rằng:

Chỉ cần ra khỏi đỉnh đầu của tôi, đây là một vài {lý do tại sao điều này đã không được làm xong}. (1) Làm cách nào để bạn chỉ định rõ ràng rằng bạn muốn có thông tin về phương thức của một triển khai giao diện rõ ràng cụ thể? (2) Điều gì xảy ra nếu độ phân giải quá tải có thể bỏ qua một phương pháp cụ thể vì nó không thể truy cập được? Nó là hợp pháp để có được phương pháp infos của phương pháp mà không thể truy cập; siêu dữ liệu luôn công khai ngay cả khi nó mô tả chi tiết riêng tư. Chúng ta có nên làm cho nó không thể nhận được siêu dữ liệu riêng, làm cho tính năng yếu, hoặc chúng ta nên làm cho nó có thể, và làm cho infoof sử dụng một thuật toán phân giải quá tải khác nhau tinh tế hơn phần còn lại của C#? (3) Làm thế nào để bạn xác định rằng bạn muốn thông tin, ví dụ, một bộ lập chỉ mục, hoặc trình thu thập thuộc tính hoặc trình bổ sung trình xử lý sự kiện?

5

Có một số mục khiến loại tính năng này trở nên khó khăn. Một trong những nguyên tắc chính là các phương thức quá tải.

class Example { 
    public void Method() {} 
    public void Method(int p1) {} 
} 

MethodInfo nào sau đây sẽ trở về?

var info = memberinfo(Example.Method); 

Như Wesley đã chỉ ra rằng, Eric's Blog có toàn bộ thảo luận về vấn đề này.

+1

Ví dụ của bạn hơi lệch, vì 'Type.GetMethod()' sẽ không hoạt động trong trường hợp này, ... nó ném một 'AmbiguousMatchException'. Trong khi các thách thức cú pháp tồn tại để thực hiện 'infoof', nó chắc chắn sẽ làm cho mã phản chiếu nhạy cảm hơn một chút duy trì được. Liệu 'infoof' có đủ giá trị so với tất cả các cải tiến có thể khác đối với ngôn ngữ C# hay không là một câu hỏi khác hoàn toàn. – LBushkin

+0

Nó có thể trả về một mảng với tất cả các tình trạng quá tải. – ja72

+0

@LBushkin không chắc chắn làm thế nào mà làm cho ví dụ của tôi tắt. Nó chỉ ra những khó khăn trong việc định hướng các phương thức quá tải với tính năng giả định 'memberinfo'. – JaredPar

1

Có rất nhiều lý do tại sao thời gian biên dịch viên phản ánh vẫn chưa được thực hiện trong C# - nhưng hầu hết trong số họ về cơ bản đun sôi xuống opportunity cost - có rất nhiều ngôn ngữ khác tính năng và cải tiến cung cấp lợi ích hơn cho người dùng hơn. Cũng có cân nhắc rằng cú pháp infoof có thể phức tạp, khó hiểu và cuối cùng kém hiệu quả hơn so với việc sử dụng phản chiếu dựa trên chuỗi. Nó cũng sẽ không phải là một sự thay thế hoàn toàn cho sự phản chiếu vì trong nhiều trường hợp siêu dữ liệu được thao tác không được biết đến lúc biên dịch.

Tuy nhiên, tất cả không bị mất, có một số thủ thuật mà bạn có thể sử dụng để thực hiện phản xạ an toàn hơn một chút để tận dụng khả năng của ngôn ngữ C#. Ví dụ, chúng ta có thể tận dụng các biểu thức lambda và các cây biểu thức để trích xuất thông tin MemberInfo.Một ví dụ đơn giản là:

public static class MethodExt { 
    static MethodInfo MemberInfo(Action d) { 
     return d.Method; 
    } 
    // other overloads ... 
} 

mà hoạt động khi bạn vượt qua trong một (không nặc danh) đại biểu hành động:

MethodInfo mi = MethodExt.MemberInfo(Object.ToString); 

An thực hiện những điều trên sử dụng cây biểu thức có thể mạnh mẽ và linh hoạt hơn, nhưng cũng phức tạp hơn nhiều. Nó có thể được sử dụng để đại diện cho quyền truy cập thành viên và thuộc tính, các chỉ mục, v.v.

Vấn đề chính với tất cả các cách tiếp cận "ưa thích" này là chúng gây nhầm lẫn cho các nhà phát triển. Họ cũng không thể xử lý tất cả các trường hợp, mà thường dẫn đến một hỗn hợp không may của mã phản chiếu truyền thống và mã cây biểu hiện ưa thích. Cá nhân, trong khi các kỹ thuật như vậy là thú vị và sáng tạo, có lẽ tốt nhất là tránh nó trong mã sản xuất.

+0

'D' tuyên bố có phản ánh thời gian biên dịch! :) – nawfal

0

Bản thân tôi sử dụng cách tiếp cận đọc IL từ một phương thức ẩn danh (sử dụng không gian tên Mono.Reflection) và lấy thông tin của mã thông báo cuối cùng được tìm thấy trong phương pháp ẩn danh. Điều này có xu hướng là cách duy nhất để nhận thông tin về những thứ như add_EventHandler hoặc set_Property hoặc các biến cục bộ được chụp. Để nhận được các thuộc tính thực tế, tôi sử dụng các cây biểu thức.

Cú pháp mà tôi sử dụng là Reflect.Member<T>.InfoOf<TMember>(Func<T,TMember> memberfunc) nơi Thành viên được thay thế bằng loại tôi quan tâm. Nó chắc chắn, nhưng nó cho phép người dùng biết chính xác mã đang cố gắng làm gì. Tôi cũng có phong cách Reflect.Member cho những thứ như thống kê và nhà xây dựng. Đây là đoạn mã có liên quan ::

internal static MemberInfo GetLastMemberOfType(MethodBase method, MemberTypes memberType) 
    { 
     var instructions = method.GetInstructions(); 
     var operandtype = memberType == MemberTypes.Field ? OperandType.InlineField : OperandType.InlineMethod; 
     for (int i = instructions.Count-1; i > -1 ; i--) 
     { 
      if (instructions[i].OpCode.OperandType == operandtype) 
      { 
       return instructions[i].Operand as MemberInfo; 
      } 
     } 
     return null; 
    } 

Liệu nó có thay thế sự phản chiếu dựa trên chuỗi không? Tuyệt đối không. Liệu nó làm cho mã của tôi an toàn hơn trong khi tôi đang tái cấu trúc các giao diện và cái gì không? Chắc chắn rồi. Nó sẽ vận chuyển với sản phẩm tôi đang làm việc? Chắc là không.

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