2008-10-29 231 views
47

我不認爲這是可能的,但如果是那麼我需要它:)覆蓋默認構造

我從Wsdl.exe用命令行自動生成的代理文件工具由Visual Studio 2008.

代理輸出是部分類。我想重寫生成的默認構造函數。我寧願不修改代碼,因爲它是自動生成的。

我試圖使另一部分類,並重新定義了默認的構造函數,但不起作用。然後我嘗試使用覆蓋和新的關鍵字,但這不起作用。

我知道我可以從局部類繼承,但是這將意味着我不得不改變我們所有的源代碼,以指向新的父類。我寧願不必這樣做。

任何想法,變通或黑客?

//Auto-generated class 
namespace MyNamespace { 
    public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol { 
     public MyWebService() { 
     string myString = "auto-generated constructor"; 
     //other code... 
     } 
    } 
} 

//Manually created class in order to override the default constructor 
namespace MyNamespace { 
    public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol { 
     public override MyWebService() { //this doesn't work 
     string myString = "overridden constructor"; 
     //other code... 
     } 
    } 
} 

回答

36

這是不可能的。部分類基本上是同一類的組成部分;沒有方法可以定義兩次或重寫,並且包含構造函數。

你可以在構造函數中調用一個方法,並且只在其他部分文件中實現。

0

沒什麼我能想到的。我能想出的「最佳」方式是添加虛擬參數的ctor並使用該參數:

public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol 
{ 
    public override MyWebService(int dummy) 
    { 
     string myString = "overridden constructor"; 
     //other code... 
    } 
} 


MyWebService mws = new MyWebService(0); 
2

你不能這樣做。我建議使用可以爲其創建定義的部分方法。例如:

public partial class MyClass{ 

    public MyClass(){ 
     ... normal construction goes here ... 
     AfterCreated(); 
    } 

    public partial void OnCreated(); 
} 

其餘的應該是很自我解釋。

編輯:

我也想指出的是,你應該定義該服務,然後你就可以程序,所以你不必有實際執行引用的接口。如果你這樣做,那麼你會有其他幾個選擇。

66

我有一個類似prolem,我生成的代碼由一個DBML文件(我USNG LINQ到SQL類)創建。

在生成的類它調用一個在構造的端部稱爲OnCreated()的部分無效。

長話短說,如果你想保留的重要構造的東西生成的類爲你做(這你應該做的),然後在局部類創建以下文件:

partial void OnCreated() 
{ 
    // Do the extra stuff here; 
} 
+1

+1簡單而優雅的解決方案。 – James 2011-06-13 23:25:30

+3

現在這是一個投票困境......與OP問題無關,與L2S無關,所以不會有一個OnCreated,但你已經阻止了我將我的頭撞向桌子,所以+1我認爲。 – Ryan 2011-07-15 18:44:42

+0

@Ryan:很高興能有幫助。謝謝:-) – 2011-08-23 15:42:23

12

嗯, 我認爲一個優秀的解決方案將是如下:

//* AutogenCls.cs file 
//* Let say the file is auto-generated ==> it will be overridden each time when 
//* auto-generation will be triggered. 
//* 
//* Auto-generated class, let say via xsd.exe 
//* 
partial class AutogenCls 
{ 
    public AutogenCls(...) 
    { 
    } 
} 



//* AutogenCls_Cunstomization.cs file 
//* The file keeps customization code completely separated from 
//* auto-generated AutogenCls.cs file. 
//* 
partial class AutogenCls 
{ 
    //* The following line ensures execution at the construction time 
    MyCustomization m_MyCustomizationInstance = new MyCustomization(); 

    //* The following inner&private implementation class implements customization. 
    class MyCustomization 
    { 
     MyCustomization() 
     { 
      //* IMPLEMENT HERE WHATEVER YOU WANT TO EXECUTE DURING CONSTRUCTION TIME 
     } 
    } 
} 

這種方法也有一些缺點(如一切):

  1. 在AutogenCls類的整個構建過程中,何時準確執行MyCustomization內部類的構造函數尚不清楚。

  2. 如果需要實現MyCustomization類的IDiposable接口以正確處理MyCustomization類的非託管資源,我還不知道如何觸發MyCustomization.Dispose()方法而不觸及該AutogenCls.cs文件...(但是我告訴「又」 :)

但這種方法從自動生成的代碼提供了巨大的分離 - 全定製在不同的SRC代碼文件中分離出來。

享受:)

1

這是我認爲在語言中的設計缺陷。他們應該允許一個部分方法的多個實現,這將提供一個很好的解決方案。 以更好的方式,構造函數(也是方法)也可以簡單地標記爲部分,並且在創建對象時可以運行具有相同簽名的多個構造函數。

最簡單的解決方案可能是每超出部分類添加一個部分「構造」的方法:

public partial class MyClass{ 

    public MyClass(){ 
     ... normal construction goes here ... 
     OnCreated1(); 
     OnCreated2(); 
     ... 
    } 

    public partial void OnCreated1(); 
    public partial void OnCreated2(); 
} 

如果想局部類是不可知對方,你可以使用反射:

// In MyClassMyAspect1.cs 
public partial class MyClass{ 

    public void MyClass_MyAspect2(){ 
     ... normal construction goes here ... 

    } 

} 

// In MyClassMyAspect2.cs 
public partial class MyClass{ 

    public void MyClass_MyAspect1(){ 
     ... normal construction goes here ... 
    } 
} 

// In MyClassConstructor.cs 
public partial class MyClass : IDisposable { 

    public MyClass(){ 
     GetType().GetMethods().Where(x => x.Name.StartsWith("MyClass")) 
          .ForEach(x => x.Invoke(null)); 
    } 

    public void Dispose() { 
     GetType().GetMethods().Where(x => x.Name.StartsWith("DisposeMyClass")) 
          .ForEach(x => x.Invoke(null)); 
    } 

} 

但他們真的應該只是添加一些更多的語言結構來處理部分類。

0

對於由Visual Studio生成的Web服務代理,您不能在分部類中添加自己的構造函數(以及您可以,但它不會被調用)。相反,您可以使用[OnDeserialized]屬性(或[OnDeserializing])在Web代理類實例化的位置掛接自己的代碼。

using System.Runtime.Serialization; 

partial class MyWebService 
{ 
    [OnDeserialized] 
    public void OnDeserialized(StreamingContext context) 
    { 
     // your code here 
    } 
} 
4

其實,這是目前可能的,現在已經補充說,部分方法。這裏的DOC:

http://msdn.microsoft.com/en-us/library/wa80x488.aspx

基本上,這個想法是,你可以聲明,並在一個文件中,你所定義的部分類調用一個方法,但實際上沒有定義在該文件中的方法。在另一個文件中,您可以定義該方法。如果您正在構建方法未定義的程序集,那麼ORM將刪除對該函數的所有調用。

因此,在上述情況下,它應該是這樣的:

//自動生成的類

namespace MyNamespace { 
    public partial class MyWebService : System.Web.Services.Protocols.SoapHttpClientProtocol { 
     public MyWebService() { 
     string myString = "auto-generated constructor"; 
     OtherCode(); 
     } 
    } 
} 

partial void OtherCode(); 

//爲了覆蓋默認的構造函數手工創建的類

partial void OtherCode() 
{ 
    //do whatever extra stuff you wanted. 
} 

這是有限的,在這種特殊情況下,如果你有一個生成的文件,你需要改變,它可能不是正確的解決方案,但對於其他人偶然發現這種嘗試爲了覆蓋部分類中的功能,這可能相當有幫助。

0

有時你沒有訪問權限,或者它不允許更改默認構造函數,因此,您不能使用默認構造函數來調用任何方法。

在這種情況下,你可以創建一個虛擬參數另一個構造,使這個新的構造函數使用調用默認的構造函數「:這()」

public SomeClass(int x) : this() 
{ 
    //Your extra initialization here 
} 

而且當你創建這個新實例類,你只是通過虛擬參數是這樣的:

SomeClass objSomeClass = new SomeClass(0); 
2

的OP已經得到的是Web引用代理不生成您可以用它來攔截任何構造局部方法的問題。

我遇到了同樣的問題,我不能升級到WCF,因爲我要定位的Web服務不支持它。

我不想手動修改自動生成的代碼,因爲如果有人調用代碼生成它會變平。

我從另一個角度解決了這個問題。我知道我的初始化需要在請求之前完成,它並不需要在構建時完成,所以我就像這樣覆蓋了GetWebRequest方法。

protected override WebRequest GetWebRequest(Uri uri) 
{ 
    //only perform the initialization once 
    if (!hasBeenInitialized) 
    { 
     Initialize(); 
    } 

    return base.GetWebRequest(uri); 
} 

bool hasBeenInitialized = false; 

private void Initialize() 
{ 
    //do your initialization here... 

    hasBeenInitialized = true; 
} 

這是一個很好的解決方案,因爲它不涉及黑客自動生成的代碼,並且它適合用於SoapHttpClientProtocol自動生成的代理進行初始化登錄的OP的具體使用情況。