2013-05-13 73 views
0

我正在研究一個大型項目,其中一個基類有數千個從它派生的類(多個開發人員正在研究它們)。預計每個類都會覆蓋一組方法。我首先用一個符合可接受模式的代碼模板生成了這幾千個類文件。我現在正在編寫單元測試,以確保開發人員沒有偏離這種模式。下面是一個示例生成的類:使用反射驗證代碼與模板模式的關係

// Base class. 
public abstract partial class BaseClass 
{ 
    protected abstract bool OnTest(); 
} 

// Derived class. DO NOT CHANGE THE CLASS NAME! 
public sealed partial class DerivedClass_00000001: BaseClass 
{ 
    /// <summary> 
    /// Do not modify the code template in any way. 
    /// Write code only in the try and finally blocks in this method. 
    /// </summary> 
    protected override void OnTest() 
    { 
     bool result = false; 
     ComObject com = null; 
     // Declare ALL value and reference type variables here. NOWHERE ELSE! 
     // Variables that would otherwise be narrowly scoped should also be declared here. 
     // Initialize all reference types to [null]. [object o;] does not conform. [object o = null;] conforms. 
     // Initialize all value types to their default values. [int x;] does not conform. [int x = 0;] conforms. 

     try 
     { 
      com = new ComObject(); 

      // Process COM objects here. 
      // Do NOT return out of this function yourself! 
     } 
     finally 
     { 
      // Release all COM objects. 
      System.Runtime.InteropServices.Marshal.ReleaseComObject(com); 

      // Set all COM objects to [null]. 
      // The base class will take care of explicit garbage collection. 
      com = null; 
     } 

     return (result); 
    } 
} 

在單元測試中,我已經能夠驗證經由反射下列:

  • 類從[BaseClass的]派生並沒有實現任何接口。
  • 類名符合模式。
  • catch塊沒有被過濾。
  • 沒有添加其他的catch塊。
  • 沒有聲明任何級別的字段或屬性。
  • 所有方法值類型變量在聲明時都被手動初始化。
  • 沒有其他方法添加到派生類。

以上是很容易通過反射來實現,但我主張用下面的列表中掙扎:

  • catch塊重新拋出捕獲的異常,而不是包裝,或拋出一些其他異常。
  • 末尾的[return (result);]行尚未修改,並且未添加任何其他[return (whatever);]調用。不知道如何實現這一點。
  • 驗證所有實現IDisposable的引用類型已經處理完畢。
  • 確認在[finally]塊中已經手動取消參考[System .__ ComObject]類型的所有參考類型並將其設置爲[null]。

我曾經想過解析源代碼,但除非絕對必要,否則我不喜歡這種解決方案。這是混亂的,除非我有表達樹,幾乎不可能保證成功。

任何提示將不勝感激。

+3

只是一個想法:如果方法*需要*被覆蓋,爲什麼他們是'虛擬'而不是'抽象'? – 2013-05-13 14:16:31

+0

更正了它。自從我在SO編輯器中寫一個例子以來,我就錯了。 – 2013-05-13 14:40:27

回答

6

的幾點思考:

  1. 如果方法需要被重寫,爲什麼他們virtual代替abstract
  2. 不應該改變的代碼不屬於派生類。它屬於基類。
  3. catch { throw; }沒用。去掉它。
  4. void方法返回布爾值會導致編譯器錯誤。
  5. 設置局部變量爲null沒用。
  6. 並非所有的參考類型都實現IDisposable

一般:你的大多數需求似乎沒有商業價值。

  • 爲什麼禁止實施的接口?
  • 爲什麼禁止宣告其他方法?
  • 爲什麼禁止catch子句?

你真的應該考慮一下你的實際業務需求是什麼,在他們之後你的類模型。如果這些課程需要履行某個合同,則對該合同進行建模。將實現留給實現者。


關於提出的實際問題:
這裏不能使用反射。您可以分析已編譯程序集的原始源代碼或IL代碼。
這兩個選項都非常棘手,而且在您有限的時間內很可能無法實現。我認爲修復這個架構所需的時間比實現這些選項所需的時間要少。

+1

+爲何擁有多達1億個類名? :) – 2013-05-13 14:23:30

+0

我輸入了一個簡單的例子,所以有錯誤。虛擬固定。捕獲塊被刪除。返回類型固定。當然,它適用於一次性使用。接下來,這個項目非常龐大而笨重,我們沒有時間或預算來干預建築。這些派生類的用途非常狹窄,我需要確保它符合這些標準。你的回答沒有解決我的任何問題。 – 2013-05-13 14:47:09

+0

@RaheelKhan:爲您的問題添加了明確的答案。 – 2013-05-13 14:53:54

0

雖然我敢肯定,你有一個很好的理由這樣的剛性需求...你認爲一個lambda的/代表/動作傳遞給測試功能呢?

能不能解決所有問題,但將更多的邏輯給你一些你想要的行爲(例如不能返回,不能有一流水平的變量,任何地方,但規定不能寫代碼)。

最大的擔心是捕獲變量......但可能會有解決方法。

示例代碼:

//I'd make a few signatures.... 
bool OnTest<T1, T2> (Action<ComObject, T1, T2> logic, T1 first, T2 second) 
    { 
     bool result = false; 
     ComObject com = null; 

     //no checks needed re parameters 
     //Can add reflection tests here if wanted before code is run. 

     try 
     { 
      com = new ComObject(); 
      //can't return 
      logic(com, first,second); 
     } 
     finally 
     { 
      // Release all COM objects. 
      System.Runtime.InteropServices.Marshal.ReleaseComObject(com); 

      // Set all COM objects to [null]. 
      // The base class will take care of explicit garbage collection. 
      com = null; 

      //If you want, we can check each argument and if it is disposable dispose. 
      if (first is IDisposable && first != null) ((IDisposable) first).Dispose(); 
      ... 
     } 

     return (result); //can't be changed 
    } 

不知道這是否會工作,但它只是一個想法。噢,作爲一個想法,它不是徹底的或測試 - 我希望你大大發展。

+0

謝謝。除非我錯過了某些東西,否則你可能誤解了這種情況。爲許多類生成函數框架,然後個別開發人員填充它們。作爲示例,'[ComObject com = null;]'不是模板的一部分。所以我不確定你的方法如何適合這裏。 – 2013-05-13 17:34:21

+0

「所以我不確定你的方法如何適合這裏。」不要試圖通過堅持人們遵守任意規則來強制執行這種模式,您可以使用內置語言功能來爲您執行這些限制。 Com對象可以在邏輯lambda中聲明,在arg創建函數中創建,作爲參數傳入等。 – NPSF3000 2013-05-13 23:19:11

+0

嗯......你能指導我如何使用這些語言特性來執行這樣的規則。 – 2013-05-13 23:32:10

2

您可以嘗試在這裏使用Roslyn CTP如果完全自動化的代碼分析是你真正需要的。它具有比反射更高級的語法和語義分析功能。但它仍然是很多工作。直接與開發人員,而不是他們的代碼,準備模板,指導方針可能會更省時。

+0

謝謝。這看起來很有趣。我正在探索CodeDom,但經過一番研究後,可能會與Roslyn一起工作。是的,這是很多工作,儘管我們已經有了模板生成和開發指南,但驗證數以千計的細微模式偏差的類是一場噩夢,除非您有一定程度的自動化分析的信心。從那裏開始,邏輯驗證和測試只需要很少的時間。 – 2013-05-13 17:30:32