2012-10-24 47 views
3

說我有這樣大量的樣板代碼:有沒有辦法使用PostSharp使構造函數參數在類級別可見?

class MyClass 
{ 
    private readonly IDependencyA dependencyA; 
    private readonly IDependencyB dependencyB; 

    public MyClass(
     IDependencyA dependencyA, 
     IDependencyB dependencyB) 
    { 
     if(dependencyA == null) throw ArgumentNullException("dependencyA"); 
     if(dependencyB == null) throw ArgumentNullException("dependencyB"); 
     this.dependencyA = dependencyA; 
     this.dependencyB = dependencyB; 

     ... 
    } 

    ... 

    public void SomeMethod() 
    { 
     this.dependencyA.DoSomething(this.dependencyB); 
    } 
} 

是否有使用類似PostSharp除去樣板代碼,使它看起來像這樣的方式:

class MyClass 
{ 
    [ConstructorParametersAreClassMembers] 
    public MyClass(
     IDependencyA dependencyA, 
     IDependencyB dependencyB) 
    { 
     ... 
    } 

    ... 

    public void SomeMethod() 
    { 
     this.dependencyA.DoSomething(this.dependencyB); 
    } 
} 

是這樣甚至可能嗎?

另外:這實際上是它在F#中默認工作的方式。

回答

3

這是可能的,但不是一個非常有吸引力的方法。我明白了痛苦。我發現C#在這一點上有點冗長。當應用SOLID原則時,你會得到許多小而集中的課程。由於它們很小,編寫構造函數的開銷會變大。

但不是使用PostSharp等代碼編織工具,也可以創建T4模板來爲您生成構造函數。有一個T4ConstructorGenerator NuGet包,它將T4模板添加到您的項目中,爲您生成一個構造函數。

有了這個模板下面的類:

public class SomeService 
{ 
    private readonly ITimeProvider timeProvider; 
    private readonly ILogger logger; 
    private readonly IOrderCalculator calculator; 
    private readonly IMailSender mailSender; 

    public void SomeMethod() 
    { 
     // using the dependencies 
    } 
} 

將得到以下構造:

public SomeService(
     ITimeProvider timeProvider, 
     ILogger logger, 
     IOrderCalculator calculator, 
     IMailSender mailSender) 
    { 
     if (timeProvider == null) throw new ArgumentNullException("timeProvider"); 
     if (logger == null) throw new ArgumentNullException("logger"); 
     if (calculator == null) throw new ArgumentNullException("calculator"); 
     if (mailSender == null) throw new ArgumentNullException("mailSender"); 

     this.timeProvider = timeProvider; 
     this.logger = logger; 
     this.calculator = calculator; 
     this.mailSender = mailSender; 

     this.OnCreated(); 
    } 

    partial void OnCreated(); 

模板做到這一點通過增加部分類,所以剩下原來的代碼不會受到影響。該模板只會在以下情況下添加構造函數:

  • 該類(及其相應的部分類)沒有定義任何構造函數。
  • 該類不是靜態的。
  • 該類包含一個或多個專用字段。

在你的構造往往含有額外的初始化(這實際上做的依賴注入的時候應該是罕見的)的情況下,你可以簡單地實現在現實類部分OnCreated方法,如下所示:

partial void OnCreated() 
{ 
    // do logic here 
} 
+0

這很酷,但如果我需要在構造函數中運行某種其他初始化代碼會發生什麼?也許我可以改變它,所以它調用了一個我不得不實現的'private'無參數構造函數。 –

+0

T4模板在其自己的文件中生成一個帶有構造函數的分類;它不會改變原來的類(除非它可能將類標記爲「部分」)。如果您需要「自定義」構造函數,只需將其添加到類中,並且生成的構造函數將消失。順便說一句。在執行依賴注入時,在服務類中進行任何其他初始化應該是非常不尋常的。 – Steven

+0

當然,但我的構造函數可能90%實際上是在構造函數中進行一些初始化,所以這不起作用。我意識到它不能在原始文件中創建構造函數,但是直到我添加一個之後纔會編譯。你將不得不修改T4腳本來忽略私人構造函數,當決定什麼類添加部分類... –

0

這只是一個方法中的防禦性編程,PostSharp或其他AOP工具當然可以處理,但是我看着那些代碼,它似乎是架構中出現其他問題的症狀。

您是否使用控制反轉容器/依賴注入工具(如StructureMap,Ninject等)?如果是這樣,那麼它應該處理你的依賴關係,並且如果你忘記連接某些東西,它會拋出異常。因此,這減少了所有防禦性編程的需求,同時仍然允許您將其他初始化代碼放入構造函數中。

+1

Scott試圖解決的問題是消除C#編譯器給我們的冗長。當你關注SRP時,類會變得更小,編寫構造函數的開銷會變得更大。但我必須承認,我通常不會在構造函數中寫任何警戒條款,因爲我的DI容器會保證注入非空值。但是,所有這些構造函數參數都必須映射到私有實例字段。我真的很喜歡C#在這方面發展,如[請求](http://bit.ly/WqltjH),但我知道這個功能永遠不會被添加。 – Steven

相關問題