2009-12-13 42 views
12

Tôi đang đọc và tìm hiểu về sự phản chiếu trong C#. Sẽ tốt hơn nếu biết nó có thể giúp tôi trong công việc hàng ngày như thế nào, vì vậy tôi muốn những người có nhiều kinh nghiệm hơn tôi cho tôi biết các mẫu hoặc ý tưởng về những thứ chúng ta có thể đạt được khi sử dụng, hoặc làm cách nào để giảm số lượng mã mà chúng ta viết.Phản ánh. Những gì chúng ta có thể đạt được bằng cách sử dụng nó?

Cảm ơn.

+1

câu hỏi liên quan: http://stackoverflow.com/questions/1859902/in-3-minutes-what-is-reflection –

+1

liên quan có, nhưng cá nhân tôi nghĩ rằng câu hỏi đó là khá vô ích. Tích hợp là đạo hàm ngược lại là phép tính, nhưng tôi cá là nói với bạn rằng bạn đã dạy bạn không có gì, ngay cả khi bạn biết đạo hàm là gì. : D –

Trả lời

10

Gần đây tôi đã sử dụng nó để thêm tùy chỉnh thuộc tính cho các trường trong enum của tôi:

public enum ShapeName 
{ 
    // Lines 
    [ShapeDescription(ShapeType.Line, "Horizontal Scroll Distance", "The horizontal distance to scroll the browser in order to center the game.")] 
    HorizontalScrollBar, 
    [ShapeDescription(ShapeType.Line, "Vertical Scroll Distance", "The vertical distance to scroll the browser in order to center the game.")] 
    VerticalScrollBar, 
} 

Sử dụng phản ánh để có được trên sân:

public static ShapeDescriptionAttribute GetShapeDescription(this ShapeName shapeName) 
    { 
     Type type = shapeName.GetType(); 
     FieldInfo fieldInfo = type.GetField(shapeName.ToString()); 
     ShapeDescriptionAttribute[] attribs = fieldInfo.GetCustomAttributes(typeof(ShapeDescriptionAttribute), false) as ShapeDescriptionAttribute[]; 

     return (attribs != null && attribs.Length > 0) ? attribs[0] : new ShapeDescriptionAttribute(ShapeType.NotSet, shapeName.ToString()); 
    } 

Lớp thuộc tính:

[AttributeUsage(AttributeTargets.Field)] 
public class ShapeDescriptionAttribute: Attribute 
{ 
    #region Constructor 
    public ShapeDescriptionAttribute(ShapeType shapeType, string name) : this(shapeType, name, name) { } 

    public ShapeDescriptionAttribute(ShapeType shapeType, string name, string description) 
    { 
     Description = description; 
     Name = name; 
     Type = shapeType; 
    } 
    #endregion 

    #region Public Properties 
    public string Description { get; protected set; } 

    public string Name { get; protected set; } 

    public ShapeType Type { get; protected set; } 
    #endregion 
} 
9

Nói chung Reflection cho phép bạn truy cập siêu dữ liệu về các đối tượng. Kết hợp Reflection với các kỹ thuật khác cho phép bạn làm cho chương trình của bạn năng động hơn. Ví dụ bạn có thể tải một DLL và xác định xem nó có chứa một thực hiện của một giao diện. Bạn có thể sử dụng điều này để khám phá chức năng hỗ trợ của dll khi chạy. Sử dụng có thể sử dụng điều này để mở rộng một ứng dụng mà không cần biên dịch lại và không phải khởi động lại nó.

Intellisense trong Visual Studio sử dụng sự phản chiếu để cung cấp cho bạn thông tin về các đối tượng bạn đang sử dụng.

Lưu ý rằng việc sử dụng Reflection có tính phí. Phản ánh một đối tượng có thể chậm. Nhưng nếu bạn cần nó Reflection là một công cụ rất hữu ích.

+1

Bạn có thể giảm thiểu các chi phí đó theo nhiều cách khác nhau; mã dựa trên phản chiếu có thể nhanh như mã thông thường. –

0

Tôi chỉ sử dụng phản chiếu trong mã sản xuất một lần. Đó là một tình huống mà tôi phải điều chỉnh những gì - cho đến thời điểm đó - đã được chuẩn hóa cách sử dụng của một phương thức lớp cụ thể trong một thói quen khởi động (xin lỗi không được specfic hơn - nó đã được một thời gian trước và các chi tiết mơ hồ). Cách duy nhất làm tròn vấn đề là giới thiệu một phiên bản khác của phương thức và kiểm tra các tiêu chuẩn/điều kiện mã khác nhau vv trong thời gian chạy để xác định phương pháp nào tôi nên gọi. Đó là một đoạn mã khá nhỏ gọn cung cấp một giải pháp succint cho những gì nếu không sẽ là một vấn đề lộn xộn để giải quyết.

0

Dưới đây là một số điều mà tôi đã sử dụng Reflection cho rằng sẽ là vô cùng khó khăn hoặc không thể không có nó:

  • My C# cảng của động cơ StringTemplate khuôn mẫu. Phản ánh được sử dụng để truy xuất lại các thuộc tính của các đối tượng động.
  • Trình biên dịch JIT CLI được viết bằng mã được quản lý.

Các Managed Extensibility Framework (thư viện .NET mới) sử dụng phản ánh để:

  • Xác định vị trí và soạn phần, bao gồm cả nhập khẩu áp dụng.
  • Nó tránh các cụm tải để thực thi cho đến khi nội dung của chúng được yêu cầu.
2

Một trong nhiều cách sử dụng: bạn có thể tạo kiến ​​trúc trình cắm thêm nơi bạn chỉ định tên của lớp để sử dụng trong tệp cấu hình. Sử dụng sự phản chiếu, bạn có thể lấy chuỗi này và tạo một thể hiện của đối tượng được yêu cầu. Nếu đối tượng đó thực hiện một giao diện đã biết, thì bạn có thể sử dụng nó thông qua mã thông thường (không phản chiếu).

1

Tôi đã sử dụng sự phản chiếu để cho phép tôi linh hoạt hơn đáp ứng yêu cầu thay đổi liên tục. Đó là, khách hàng tiếp tục thay đổi suy nghĩ của họ về vị trí đặt một bảng cơ sở dữ liệu trong cơ sở dữ liệu. Tất cả những gì tôi làm là có đối tượng tự kiểm tra các trường của nó và gọi các hàm tạo đối tượng của các trường đó trong chính đối tượng đó. Sau đó, nếu một bảng nên được tìm thấy ở một nơi khác? Nhấp, dán, xong.

Điều này đã không đi ra ngoài trong sản xuất cuối cùng, nhớ bạn, nhưng trong giai đoạn lặp lại đã xóa một số bản mẫu mà tôi cần thay đổi.

1

Tôi đã sử dụng sự phản chiếu để tạo thuận lợi cho việc dịch các nút điều khiển như nhãn và nút trên biểu mẫu của chúng tôi. Sử dụng sự phản chiếu Tôi sẽ đi qua tất cả các điều khiển trên biểu mẫu của tôi và viết tên điều khiển, văn bản và tiêu đề cho một tệp XML. Sau khi tiêu đề điều khiển và văn bản được dịch trong XML, tệp được đọc lại trong việc đặt tiêu đề và văn bản của mọi điều khiển được tìm thấy trong XML thành các giá trị đã dịch của nó.
Biểu mẫu của chúng tôi cần được dịch sang nhiều ngôn ngữ khác nhau và việc sử dụng sự phản chiếu đã giúp chúng tôi tiết kiệm rất nhiều thời gian.

-1

Sử dụng cổ điển tôi có cho nó khi sử dụng Red Gate .Net Reflector để hiểu rõ hơn về cơ chế của chính khuôn khổ .Net. Bao giờ tự hỏi làm thế nào hoặc lý do tại sao một đối tượng khung đặc biệt hoạt động theo cách nó làm hoặc có bao giờ bạn đã được một chút stumped như quá tại sao somethng không hoạt động theo cách bạn nghĩ rằng nó sẽ? Đôi khi các tài liệu có thể là một chút tồi tàn để nói rằng ít nhất nhưng bằng cách sử dụng sự phản ánh và công cụ của Redgate bạn có thể sniff về trong khuôn khổ mã để hiểu rõ hơn về cách/tại sao/tất cả những gì của nó.

Đã tìm thấy nhiều lỗi trong mã CLR qua "người ngoài MS" bằng cách sử dụng phản chiếu.

+1

Tôi sẽ cần phải kiểm tra, nhưng tôi không chắc chắn phản xạ sử dụng phản ánh như vậy; Tôi đã bị ấn tượng vì nó đọc và phân tích cú pháp IL trực tiếp, thay vì sử dụng API phản chiếu. –

3

Điều vô giá đối với mã thư viện mà không cần phải biết về người gọi - như với generics, nhưng lại có nhiều quyền truy cập vào dữ liệu hơn. Ví dụ:

  • ORMs (materialization vv)
  • serialization/deserialization
  • đối tượng nhân bản/bản sao sâu
  • UI/code ràng buộc (Nghiêm đây là ComponentModel, nhưng bạn có thể kết hợp hai - cho Ví dụ: HyperDescriptor)

Tất nhiên, bạn nên cố gắng giảm thiểu số lượng phản ánh mà bạn làm, nhưng bạn có thể giảm thiểu chi phí bằng cách lưu trữ các đại biểu fr om Delegate.CreateDelegate/Expression/DynamicMethod

1

Cửa sổ thuộc tính trong VS là phản ánh dựa - nếu bạn thực hiện một điều khiển người dùng mà bạn có thể sửa đổi bất kỳ tài sản trên nó từ PropertyGrid (nó cũng là một điều khiển mà bạn có thể sử dụng nếu bạn muốn) ngay lập tức. Tất nhiên bạn có thể thêm các thuộc tính để nâng cao cách nó được hiển thị (được truy cập thông qua sự phản chiếu).

Tôi cũng đã sử dụng nó để triển khai lớp tuần tự nhị phân tùy chỉnh.

Ở đây tôi có một lớp nơi tôi sử dụng sự phản chiếu để sắp đặt từng hàng/de-tuần tự hóa - và cung cấp các thuộc tính cho thông tin giao diện người dùng bổ sung.

[TypeConverter(typeof(IndexedExpandableObjectConverter))] 
[BinarySerializeable] 
public sealed class Socket 
{ 
    #region Fields (7)  

    [SerializedPosition(0)] 
    Byte _mode = 1; 

    ... 

    [SerializedPositionAttribute(4)] 
    UInt16 _localPort; 

    ... 

#region Thuộc tính (5)

[DisplayName("Listning Port")] 
    [Description("The port which the socket will listen for connections on")] 
    [DisplayIndex (0)] 
    public UInt16 LocalPort 
    { 
     get { return _localPort; } 
     set { _localPort = value; } 
    } 

    ... 

Và chức năng serialization - như bạn có thể thấy, nó chỉ mất một đối tượng và thứ tự byte (endianness) mà bạn muốn. Mọi thứ khác được xác định bằng sự phản chiếu. Mặc định SerializationProvider hoạt động bằng cách sử dụng các thuộc tính SerializedPosition trên các trường trong đối tượng (riêng tư hay không).

public static Byte[] Serialize(Object obj, ByteOrder streamOrder) 
{ 

    var provider = GetProvider(obj); 

    if (provider.CanSerialize(obj.GetType())) 
     return provider.Serialize(obj, streamOrder); 

    throw new ArgumentException(obj.GetType() + " is non-serialisable by the specified provider '" + provider.GetType().FullName + "'."); 
} 


private static IBinarySerializatoinProvider GetProvider(Object obj) 
{ 

    var providerAttrib = Reflector.GetAttribute<BinarySerializationProviderAttribute>(obj); 

    if (providerAttrib != null) 
     return CreateProvider(providerAttrib.ProviderType); 

    return CreateProvider(typeof(SerializationProvider)); 
} 
0

Tôi đoán rằng một ứng dụng "độc lập", nơi mọi đối tượng bạn sử dụng được biết đến tại thời gian biên dịch, bạn không sử dụng phản ánh nhiều. Khi bạn viết thư viện hoặc mã khung nên sử dụng các đối tượng không được biết (hoàn toàn - bạn có thể biết về giao diện hoặc baseclasses) tại thời gian biên dịch, sự phản chiếu có thể là vô giá để làm việc với các đối tượng đó.

1

Đây là cách để thực hiện các phương pháp dựa trên một enum hoặc một chuỗi ma thuật ...


    public enum ReflectionTestMethods 
    { 
     MethodA, 
     MethodB, 
     MethodC 
    } 
    public class ReflectionTest 
    { 

     public void Execute(ReflectionTestMethods method) 
     { 
      MethodInfo methodInfo = GetType().GetMethod(method.ToString() 
       , BindingFlags.Instance | BindingFlags.NonPublic); 
      if (methodInfo == null) throw new NotImplementedException(method.ToString()); 
      methodInfo.Invoke(this, null); 
     } 

     private void MethodA() 
     { 
      Debug.Print("MethodA"); 
     } 

     private void MethodB() 
     { 
      Debug.Print("MethodB"); 
     } 

     private void MethodC() 
     { 
      Debug.Print("MethodC"); 
     } 
    } 

Nhưng điều này là có thể là một giải pháp tốt hơn ...


    public class ActionTest 
    { 
     private readonly Dictionary _actions = new Dictionary(); 

     public ActionTest() 
     { 
      _actions.Add(ReflectionTestMethods.MethodA.ToString(), new Action(MethodA)); 
      _actions.Add(ReflectionTestMethods.MethodB.ToString(), new Action(MethodB)); 
      _actions.Add(ReflectionTestMethods.MethodC.ToString(), new Action(MethodC)); 
     } 

     public void Execute(ReflectionTestMethods method) 
     { 
      if (!_actions.ContainsKey(method.ToString())) 
       throw new NotImplementedException(method.ToString()); 
      _actions[method.ToString()](); 
     } 

     private void MethodA() 
     { 
      Debug.Print("MethodA"); 
     } 

     private void MethodB() 
     { 
      Debug.Print("MethodB"); 
     } 
     private void MethodC() 
     { 
      Debug.Print("MethodC"); 
     } 
    } 
0

tôi sử dụng nó cho:

  • Tiêm phụ thuộc
  • Cách giải quyết cho Microsofts thiếu động lực để thêm những thứ như "hiệp biến/contravariant chung chung" và "mới() ràng buộc với các thông số"
  • hướng Aspect lập trình (đến một mức độ nào, chủ yếu là tôi sử dụng PostSharp)
0

Reflections được tốt đẹp cho "cuối ràng buộc" các giải pháp mà bạn không muốn có tham chiếu vật lý được kết nối với dự án của bạn mà là "kết nối" nó sau này. Bằng cách đó, nếu tài liệu tham khảo không có ở đó và nó không quan trọng, bạn sẽ không nhận được các lỗi không xác định của các tham chiếu bị thiếu. Bạn nhận được một lỗi kiểm soát mà bạn có thể xử lý.

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