2008-10-29 324 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的具体使用情况。