53

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

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

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

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

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

有什么想法、解决方法或技巧吗?

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

12 回答 12

70

我遇到了类似的问题,我生成的代码是由 DBML 文件创建的(我正在使用 Linq-to-SQL 类)。

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

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

partial void OnCreated()
{
    // Do the extra stuff here;
}
于 2010-01-09T01:24:52.737 回答
40

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

您可以在构造函数中调用一个方法,并且只在其他部分文件中实现它。

于 2008-10-29T18:08:00.987 回答
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 类的非托管资源的处置,我不知道(尚)如何在不触及 AutogenCls.cs 文件的情况下触发 MyCustomization.Dispose() 方法...(但正如我所说的'还':)

但是这种方法与自动生成的代码有很大的分离——整个定制是在不同的 src 代码文件中分离的。

请享用 :)

于 2010-04-02T20:57:23.660 回答
4

实际上,现在这是可能的,因为已经添加了部分方法。这是文档:

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

它有点有限,在这种特殊情况下,如果您有一个需要更改的生成文件,它可能不是正确的解决方案,但对于其他偶然发现此尝试覆盖部分类中的功能的人来说,这可以很有帮助。

于 2011-09-27T15:52:40.500 回答
3

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;
}

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

于 2013-06-17T16:06:36.670 回答
2

你不能这样做。我建议使用部分方法,然后您可以为其创建定义。就像是:

public partial class MyClass{ 

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

    public partial void OnCreated();
}

其余的应该是不言自明的。

编辑:

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

于 2008-10-29T18:10:25.787 回答
2

我想你也许可以用PostSharp做到这一点,看起来有人已经为生成的部分类中的方法做了你想要的。我不知道这是否会很容易地转化为编写方法并让它的主体替换构造函数的能力,因为我还没有尝试过,但似乎值得一试。

编辑:这是相同的路线,看起来也很有趣。

于 2008-10-29T18:28:24.360 回答
2

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

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

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

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

SomeClass objSomeClass = new SomeClass(0);
于 2012-02-14T09:49:03.997 回答
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));
    }

}

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

于 2010-12-30T11:54:42.240 回答
0

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

using System.Runtime.Serialization;

partial class MyWebService
{
     [OnDeserialized]
     public void OnDeserialized(StreamingContext context)
     {
         // your code here
     }
}
于 2011-02-22T09:53:32.267 回答
0

我并没有完全解决 OP,但是如果您碰巧正在使用 EntityFramework Reverse POCO Generator 生成类,那么在构造函数中调用了一个部分方法,这对于初始化您通过自己的部分类添加的内容非常方便。 .

工具生成:

   [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();
    }

由您添加:

    public partial class Library {
        List<Book> Books { get; set; }
        partial void InitializePartial() {
            Books = new List<Book>();
        }
    }

    public class Book {
        public string Title { get; set; }
    }
于 2019-09-18T19:16:27.103 回答
-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);
于 2008-10-29T18:07:04.903 回答