使用另一个部分类覆盖部分类的默认构造函数

时间:2008-10-29 18:02:37

标签: c# web-services wsdl override partial-classes

我不认为这是可能的,但如果是的话我需要它:)

我有一个来自Visual Studio 2008的wsdl.exe命令行工具的自动生成的代理文件。

代理输出是部分类。我想覆盖生成的默认构造函数。我宁愿不修改代码,因为它是自动生成的。

我尝试制作另一个部分类并重新定义默认构造函数,但这不起作用。然后我尝试使用覆盖和新关键字,但这不起作用。

我知道我可以继承部分类,但这意味着我必须将所有源代码更改为指向新的父类。我宁愿不必这样做。

任何想法,解决方法或黑客攻击?

//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...
      }
   }
}

12 个答案:

答案 0 :(得分:66)

我有一个类似的问题,我生成的代码是由dbml文件创建的(我使用的是Linq-to-SQL类)。

在生成的类中,它在构造函数的末尾调用一个名为OnCreated()的部分void。

长话短说,如果你想保留生成的类为你做的重要构造函数(你可能应该这样做),那么在你的partial类中创建以下内容:

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

答案 1 :(得分:37)

这是不可能的。 部分类基本上是同一类的一部分;没有方法可以定义两次或重写,包括构造函数。

您可以在构造函数中调用方法,只在其他零件文件中实现它。

答案 2 :(得分:13)

嗯, 我认为一个优雅的解决方案如下:

//* 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()的情况下触发MyCustomization.Dispose()方法触摸AutogenCls.cs文件......(但正如我告诉'尚':)

  3. 但是这种方法与自动生成的代码有很大的区别 - 整个自定义在不同的src代码文件中分开。

    享受:)

答案 3 :(得分:3)

实际上,现在可以添加部分方法了。这是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.
}

它有点受限,在这种特殊情况下,你有一个你需要改变的生成文件,它可能不是正确的解决方案,但对于那些偶然发现这个试图覆盖部分类中的功能的人来说,这可能非常有用。

答案 4 :(得分:3)

OP遇到的问题是Web引用代理不会生成任何可用于拦截构造函数的部分方法。

我遇到了同样的问题,我不能只升级到WCF,因为我所针对的网络服务不支持它。

我不想手动修改自动生成的代码,因为如果有人调用代码生成它会变得扁平化。

我从不同的角度解决了这个问题。我知道我的初始化需要在请求之前完成,它不需要在构造时完成,所以我只是覆盖了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;
}

这是一个很好的解决方案,因为它不涉及黑客自动生成的代码,并且它符合OP为SoapHttpClientProtocol自动生成的代理执行初始化登录的确切用例。

答案 5 :(得分:2)

你不能这样做。我建议使用部分方法,然后您可以为其创建定义。类似的东西:

public partial class MyClass{ 

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

    public partial void OnCreated();
}

其余的应该是非常自我解释的。

编辑:

我还想指出,您应该为此服务定义一个接口,然后您可以对其进行编程,因此您不必参考实际的实现。如果你这样做,那么你还有其他一些选择。

答案 6 :(得分:2)

我想你可以用PostSharp做到这一点,看起来有人做了want for methods in generated partial classes。我不知道这是否会很容易转化为编写方法的能力,并让它的主体替换构造函数,因为我还没有给它一个镜头,但它似乎值得一试。

编辑:this is along the same lines,看起来也很有趣。

答案 7 :(得分: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));
    }

}

但实际上他们应该添加一些语言结构来处理部分类。

答案 8 :(得分:0)

对于Visual Studio生成的Web服务代理,您不能在分部类中添加自己的构造函数(您可以,但不会调用它)。相反,您可以使用[OnDeserialized]属性(或[OnDeserializing])在实例化Web代理类的位置挂钩您自己的代码。

using System.Runtime.Serialization;

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

答案 9 :(得分:0)

有时您没有访问权限或者不允许更改默认构造函数,因此您无法使用默认构造函数来调用任何方法。

在这种情况下,您可以使用伪参数创建另一个构造函数,并使用“:this()”

使此新构造函数调用默认构造函数
public SomeClass(int x) : this()
{
    //Your extra initialization here
}

当您创建此类的新实例时,您只需传递如下虚拟参数:

SomeClass objSomeClass = new SomeClass(0);

答案 10 :(得分:0)

我还没有完全解决OP,但是如果您碰巧正在使用EntityFramework反向POCO生成器生成类,则构造函数中有一个局部方法,该方法可用于初始化通过局部类添加的内容拥有...

由工具生成:

=iif(Variables!PAT_ID_Count.Value = 0, "PASS", 
     iif(IsNothing(Variables!Summary.Value), "FAIL","" ))

由您添加:

   [System.CodeDom.Compiler.GeneratedCode("EF.Reverse.POCO.Generator", "2.37.3.0")]
    public partial class Library {
        public string City { get; set; }
        public Library() {
            InitializePartial();
        }
        partial void InitializePartial();
    }

答案 11 :(得分:-1)

我无法想到任何事情。我能想出的“最佳”方法是添加一个带有伪参数的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);