2008-09-06 51 views
10

我想知道在C#代碼中反射的恰當性。例如,我編寫了一個函數,它遍歷給定源對象的屬性並創建指定類型的新實例,然後將具有相同名稱的屬性值從一個複製到另一個。我創建了這個將數據從一個自動生成的LINQ對象複製到另一個,以解決LINQ中多個表的繼承問題。在C中反射的理由#

但是,我不禁想到像這樣的代碼真的是「作弊」,即不是使用提供的語言結構來實現給定的目標,而是允許您規避它們。

這種代碼在什麼程度上可以接受?有什麼風險?這種方法的合理用途是什麼?

回答

1

它可能只是我,但我的方式是通過創建一個代碼生成器 - 在運行時使用反射是有點昂貴和無類型。創建根據最新代碼生成的類並以強類型方式複製所有內容將意味着您將在構建時捕獲這些錯誤。

例如,生成的類可能是這樣的:

static class AtoBCopier 
{ 
    public static B Copy(A item) 
    { 
     return new B() { Prop1 = item.Prop1, Prop2 = item.Prop2 }; 
    } 
} 

如果任一類不具備的特性或它們的類型改變,代碼不能編譯。另外,這個時代有很大的改善。

2

我同意,它給我的它的作品,但它感覺像一個黑客感覺。儘可能避免反思。在重構了代碼中的代碼後,我被燒了很多次。代碼編譯得很好,測試甚至可以運行,但是在特殊情況下(測試沒有涉及),程序由於重構了反射代碼中的一個對象而重新運行。

示例1: OR映射器中的反射,您更改對象模型中屬性的名稱或類型:拋出運行時。

示例2:您身處SOA商店。 Web服務是完全分離的(或者你認爲)。他們有自己的一套生成的代理類,但在映射你決定節省一些時間和你這樣做:

ExternalColor c = (ExternalColor)Enum.Parse(typeof(ExternalColor), 
              internalColor.ToString()); 

在幕後,這也是反映,由.NET Framework本身完成。現在如果您決定重命名InternalColor.GreyInternalColor.Gray會發生什麼情況?一切看起來都不錯,它建立的很好,甚至可以正常運行..直到一天愚蠢的用戶決定使用灰色......在這一點上映射器將炸燬。

8

有時使用反射可能有點破解,但很多時候它只是最奇妙的代碼工具。

看看.Net屬性網格 - 任何使用過Visual Studio的人都會熟悉它。你可以將它指向任何對象,它會產生一個簡單的屬性編輯器。這使用反射,實際上VS的大部分工具箱都是這樣。

看看單元測試 - 它們是通過反射加載的(至少在NUnit和MSTest中)。

反射允許來自靜態語言的動態樣式行爲。

它真正需要的一件事就是鴨子打字 - C#編譯器已經支持:你可以foreach任何看起來像IEnumerable的東西,不管它是否實現接口。您可以在任何具有名爲Add的方法的類上使用C#3集合語法。

使用反射,無論你需要動態式的行爲 - 例如,你有對象的集合,並要檢查每個相同的屬性。

動態類型的風險類似 - 編譯時異常變成運行時異常。你的代碼不是'安全'的,你必須做出相應的反應。

.Net反射代碼非常快,但並不像顯式調用那樣快。

+0

如果有人問我有什麼反思和反思,這會是一個合適的答案嗎? – 2014-08-04 19:56:26

1

我最近在C#中使用反射來查找特定接口的實現。我編寫了一個簡單的批處理樣式解釋器,根據類名查找每個計算步驟的「操作」。反映當前的命名空間,然後彈出我可以執行()編輯的IStep接口的正確實現。這樣一來,增加了新的「行動」的創建一個新的派生類一樣簡單 - 沒有必要將其添加到註冊表,甚至更糟糕:忘記將其添加到註冊表...

2

反思是一個奇妙的工具我不能沒有。它可以使編程更容易和更快。

例如,我在我的ORM層中使用了反射,以便能夠從表中分配具有列值的屬性。如果不是反射,我不得不爲每個表/類映射創建一個副本類。

至於上面的外部顏色異常。問題不是Enum.Parse,但編碼器沒有捕獲到適當的異常。由於字符串被解析,編碼器應該總是假定字符串可以包含不正確的值。

同樣的問題適用於.Net中的所有高級編程。 「擁有權利的同時也被賦予了重大的責任」。使用反射給你很大的力量。但請確保您知道如何正確使用它。網上有很多例子。

0

反射使得它非常容易實現的,其中的插件DLL文件在運行時自動加載(在編譯時沒有明確的鏈接)的插件架構。

這些可以掃描實現/擴展相關接口/類的類。然後可以使用反射來按需實例化這些實例。