2009-12-13 90 views
12

我正在閱讀和學習C#中的反射。知道它在日常工作中如何能夠幫助我很好,所以我希望有比我更多經驗的人告訴我樣品或想法,我們可以使用它來實現什麼樣的事情,或者我們如何減少代碼量我們寫的。反思。我們可以使用它來實現什麼?

謝謝。

+1

相關問題:http://stackoverflow.com/questions/1859902/in-3-minutes-what-is-reflection – 2009-12-13 21:02:08

+1

相關是的,但我個人認爲這個問題是相當無益的。積分是相反的推導是微積分,但我敢打賭,告訴你,即使你知道什麼是推導,也教你幾乎沒有任何東西。 :D – 2009-12-13 23:08:08

回答

10

最近,我用它來添加自定義屬性在我的枚舉字段:

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, 
} 

使用反射來獲取字段:

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()); 
    } 

屬性類:

[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

一般來說,Reflection允許您訪問關於對象的元數據。將反射與其他技術結合使用,可以使您的程序更具活力。例如,您可以加載一個DLL並確定它是否包含接口的實現。你可以用它來發現在運行時支持功能的dll。使用可以使用它來擴展應用程序而無需重新編譯,也無需重新啓動它。

智能感知在Visual Studio中使用反射來給你,你正在使用的對象的信息。

注意,使用反射是有代價的。反射對象可能會很慢。但是,如果你需要它反射是一個非常有用的工具。

+1

您可以通過多種方式減輕這些成本;基於反射的代碼可以像常規代碼一樣快。 – 2009-12-13 22:33:07

0

我只用在生產代碼反射一次。在這種情況下,我不得不做出調整 - 到目前爲止 - 在啓動例程中已經標準化地使用了一種特定的類方法(抱歉,不要更具體 - 它是前一段時間,細節是朦朧)。解決問題的唯一方法是引入不同版本的方法,並在運行時檢查各種標準/代碼條件等,以確定我應該調用哪種方法。這是一段非常緊湊的代碼,它提供了一個解決問題的簡單方法,否則這些問題將是一個難以解決的問題。

0

這裏有一些事情我已經使用了反思,將是非常困難或不可能沒有它:

  • StringTemplate模板引擎我的C#端口。反射用於檢索動態對象的屬性。
  • 一個CLI JIT編譯器託管代碼編寫。

Managed Extensibility Framework(一個新的.NET庫)使用反射來:

  • 找到並組成部分,包括施加進口。
  • 它避免了裝載組件的執行,直到需要的內容。
2

其中一種用途:您可以製作一個插件體系結構,您可以在其中指定配置文件中使用的類的名稱。使用反射,您可以使用此字符串並創建請求的對象的實例。如果該對象實現了一個已知的接口,那麼你可以通過普通的(非反射)代碼來使用它。

1

我已經使用了反射來讓我更加靈活地滿足不斷變化的需求。也就是說,客戶在數據庫中放置數據庫表的位置不斷變化。我所做的只是讓對象自己檢查其字段並在對象本身內調用這些字段的對象構造函數。那麼,如果應該在別的地方找到一張桌子?點擊,粘貼,完成。

這並沒有在最終的生產中出現,請注意,但在迭代階段中刪除了一些我需要更改的樣板。

1

我使用反射來幫助翻譯控件,如標籤和按鈕在我們的表單上。使用反射我會瀏覽表單上的所有控件,並將控件名稱,文本和標題寫入XML文件。在XML中翻譯控件標題和文​​本後,將該XML中找到的每個控件的標題和文本設置爲已翻譯的值,從而讀回該文件。
我們的表格需要翻譯成幾種不同的語言,使用反射幫助我們節省了大量時間。

-1

我使用Red Gate .Net Reflector來更好地理解.Net框架本身的機制。曾經想知道爲什麼某個特定的框架對象會以它的方式工作,或者爲什麼某些工作不按照您認爲的方式工作?

有時候文檔可能有點破舊,但至少可以說,但通過使用反射和Redgate的工具,您可以在框架代碼中嗅探到,以便更好地理解它的方式/原因/內容。

通過使用反射的「MS外部人員」在CLR代碼中發現了一些以上的錯誤。

+1

我需要檢查,但我不確定反射鏡如何使用反射;我的印象是它直接讀取並解析IL,而不是使用反射API。 – 2009-12-13 22:32:11

3

對於沒有任何需要知道調用者的庫代碼來說,它是非常寶貴的 - 就像泛型一樣,但對數據的訪問更豐富。例子:

  • 奧姆斯(物化等)
  • 串行/解串
  • 對象克隆/深複製
  • UI /綁定代碼(嚴格這是ComponentModel,但你可以混合使用這兩種 - 爲例如,HyperDescriptor)

您當然應該嘗試儘量減少反射的數量,但您可以通過緩存代表fr來降低成本OM Delegate.CreateDelegate/Expression/DynamicMethod

1

在VS屬性窗口是基於反射 - 如果你讓一個用戶控件,你可以從PropertyGrid瞬間(其還可以,如果你想使用控制)修改它的屬性。當然,你可以添加屬性來增強它的顯示方式(通過反射來訪問)。

我也用它來實現一個自定義的二進制序列化類。

這裏我有一個類,我使用反射序列化/反序列化它 - 並提供其他UI信息的屬性。

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

    [SerializedPosition(0)] 
    Byte _mode = 1; 

    ... 

    [SerializedPositionAttribute(4)] 
    UInt16 _localPort; 

    ... 

#區域屬性(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; } 
    } 

    ... 

,系列化的功能 - 你可以看到,它只是需要一個對象和字節順序(字節序)你想要的。其他一切都是由反思決定的。默認SerializationProvider在對象內的字段上使用SerializedPosition屬性(專用或不專用)。

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

我想這一個「獨立」的應用程序,其中每一個對象,你使用在編譯時被稱爲,你不使用反射了。

但是,當編寫應該在編譯時使用未知對象(完全 - 您可能瞭解接口或基類)的庫或框架代碼時,反射對於使用這些對象來說可能是非常寶貴的。

1

這是方法來執行基於一個枚舉或魔術字符串方法...


    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"); 
     } 
    } 

但是,這也許是一個更好的解決方案...


    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

我用它來:

  • 依賴注入
  • 變通辦法微軟缺乏動機添加的東西,如「協變/逆變通用」與「新的()與參數約束」
  • 面向方面編程(在一定程度上,主要是我用PostSharp)
0

思考是很好的「後期綁定」解決方案,您不希望將物理參考連接到您的項目,而是稍後「連接」它。這樣,如果參考不存在並且不重要,則不會丟失缺少參考的錯誤。你會得到一個你可以處理的控制錯誤。

相關問題