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

发布于 2024-07-08 18:48:00 字数 945 浏览 5 评论 0原文

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

我有一个由 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...
      }
   }
}

I don't think this is possible, but if is then I need it :)

I have a auto-generated proxy file from the wsdl.exe command line tool by Visual Studio 2008.

The proxy output is partial classes. I want to override the default constructor that is generated. I would rather not modify the code since it is auto-generated.

I tried making another partial class and redefining the default constructor, but that doesn't work. I then tried using the override and new keywords, but that doesn't work.

I know I could inherit from the partial class, but that would mean I'd have to change all of our source code to point to the new parent class. I would rather not have to do this.

Any ideas, work arounds, or hacks?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

感性 2024-07-15 18:48:00

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

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

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

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

I had a similar problem, with my generated code being created by a DBML file (I'm using Linq-to-SQL classes).

In the generated class it calls a partial void called OnCreated() at the end of the constructor.

Long story short, if you want to keep the important constructor stuff the generated class does for you (which you probably should do), then in your partial class create the following:

partial void OnCreated()
{
    // Do the extra stuff here;
}
蓝天 2024-07-15 18:48:00

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

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

This is not possible.
Partial classes are essentially parts of the same class; no method can be defined twice or overridden, and that includes the constructor.

You could call a method in the constructor, and only implement it in the other part file.

知你几分 2024-07-15 18:48:00

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

//* 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 的情况下触发 MyCustomization.Dispose() 方法.cs 文件...(但正如我所说的:)

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

享受 :)

Hmmm,
I think one elegant solution would be the following:

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

This approach has some drawbacks (as everything):

  1. It is not clear when exactly will be executed the constructor of the MyCustomization inner class during whole construction procedure of the AutogenCls class.

  2. If there will be necessary to implement IDiposable interface for the MyCustomization class to correctly handle disposing of unmanaged resources of the MyCustomization class, I don't know (yet) how to trigger the MyCustomization.Dispose() method without touching the AutogenCls.cs file ... (but as I told 'yet' :)

But this approach offers great separation from auto-generated code - whole customization is separated in different src code file.

enjoy :)

作死小能手 2024-07-15 18:48:00

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

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

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

Actually, this is now possible, now that partial methods have been added. Here's the doc:

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

Basically, the idea is that you can declare and call a method in one file where you are defining the partial class, but not actually define the method in that file. In the other file, you can then define the method. If you are building an assembly where the method is not defined, then the ORM will remove all calls to the function.

So in the case above it would look like this:

//Auto-generated class

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

partial void OtherCode();

//Manually created class in order to override the default constructor

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

It is somewhat limited, and in this particular case, where you have a generated file that you'd need to alter, it might not be the right solution, but for others who stumbled on this trying to override functionality in partial classes, this can be quite helpful.

俯瞰星空 2024-07-15 18:48:00

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 自动生成的代理执行初始化登录的确切用例。

The problem that the OP has got is that the web reference proxy doesn't generate any partial methods that you can use to intercept the constructor.

I ran into the same problem, and I can't just upgrade to WCF because the web service that I'm targetting doesn't support it.

I didn't want to manually amend the autogenerated code because it'll get flattened if anyone ever invokes the code generation.

I tackled the problem from a different angle. I knew my initialization needed doing before a request, it didn't really need to be done at construction time, so I just overrode the GetWebRequest method like so.

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

This is a nice solution because it doesn't involve hacking the auto generated code, and it fits the OP's exact use case of performing initialization login for a SoapHttpClientProtocol auto generated proxy.

错々过的事 2024-07-15 18:48:00

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

public partial class MyClass{ 

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

    public partial void OnCreated();
}

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

编辑:

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

You can't do this. I suggest using a partial method which you can then create a definition for. Something like:

public partial class MyClass{ 

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

    public partial void OnCreated();
}

The rest should be pretty self explanatory.

EDIT:

I would also like to point out that you should be defining an interface for this service, which you can then program to, so you don't have to have references to the actual implementation. If you did this then you'd have a few other options.

慵挽 2024-07-15 18:48:00

我想你也许可以用 PostSharp 来做到这一点,而且看起来有人已经做了你的事情< a href="http://www.postsharp.org/forum/post1873.html" rel="nofollow noreferrer">想要生成的部分类中的方法。 我不知道这是否很容易转化为编写方法并使其主体替换构造函数的能力,因为我还没有尝试过,但似乎值得一试。

编辑: 这也是同样的思路,而且看起来也很有趣。

I am thinking you might be able to do this with PostSharp, and it looks like someone has done just what you want for methods in generated partial classes. I don't know if this will readily translate to the ability to write a method and have its body replace the constructor as I haven't given it a shot yet but it seems worth a shot.

Edit: this is along the same lines and also looks interesting.

随梦而飞# 2024-07-15 18:48:00

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

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

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

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

SomeClass objSomeClass = new SomeClass(0);

Sometimes you don't have access or it's not allowed to change the default constructor, for this reason you cannot have the default constructor to call any methods.

In this case you can create another constructor with a dummy parameter, and make this new constructor to call the default constructor using ": this()"

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

And when you create a new instance of this class you just pass dummy parameter like this:

SomeClass objSomeClass = new SomeClass(0);
活雷疯 2024-07-15 18:48:00

我认为这是该语言的设计缺陷。 他们应该允许一个部分方法的多个实现,这将提供一个很好的解决方案。
以一种更好的方式,构造函数(也是一种方法)也可以简单地标记为部分的,并且在创建对象时将运行具有相同签名的多个构造函数。

最简单的解决方案可能是为每个额外的分部类添加一个分部“构造函数”方法:

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

}

但实际上他们应该添加更多的语言构造来使用部分班级。

This is in my opinion a design flaw in the language. They should have allowed multiple implementations of one partial method, that would have provided a nice solution.
In an even nicer way the constructor (also a method) can then also be simply be marked partial and multiple constructors with the same signature would run when creating an object.

The most simple solution is probably to add one partial 'constructor' method per extra partial class:

public partial class MyClass{ 

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

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

If you want the partial classes to be agnostic about each other, you can use reflection:

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

}

But really they should just add some more language constructs to work with partial classes.

小兔几 2024-07-15 18:48:00

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

using System.Runtime.Serialization;

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

For a Web service proxy generated by Visual Studio, you cannot add your own constructor in the partial class (well you can, but it does not get called). Instead, you can use the [OnDeserialized] attribute (or [OnDeserializing]) to hook in your own code at the point where the web proxy class is instantiated.

using System.Runtime.Serialization;

partial class MyWebService
{
     [OnDeserialized]
     public void OnDeserialized(StreamingContext context)
     {
         // your code here
     }
}
静赏你的温柔 2024-07-15 18:48:00

我没有完全解决OP,但如果您碰巧使用 EntityFramework 反向 POCO 生成器生成类,则构造函数中会调用一个部分方法,该方法可以方便地初始化您自己通过部分类添加的内容。 .

由工具生成:

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

I'm not quite addressing the OP, but if you happen to be generating classes with the EntityFramework Reverse POCO Generator, there's a partial method called in the constructor which is handy for initializing things you're adding via partial classes on your own...

Generated by tool:

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

added by you:

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

    public class Book {
        public string Title { get; set; }
    }
燃情 2024-07-15 18:48:00

虽然有点晚了,但这确实是可能的。 有点儿。

我最近在我的代码生成器中执行了下面的技巧,结果令人满意。 是的,需要一个虚拟参数,但它不会引起任何重大问题。 为了保持一致性,您可能需要应用一些规则:

规则

  1. 手动创建的构造函数必须受保护
  2. 生成的构造函数必须是public,具有与受保护的构造函数相同的参数以及额外的可选虚拟参数。
  3. 生成的构造函数使用提供的所有参数调用原始构造函数。

这适用于常规构造和反射:

var s1 = new MyWebService();

var s2 = (MyWebService?)Activator.CreateInstance(
             typeof(MyWebService),
             BindingFlags.CreateInstance | BindingFlags.Public);

对于 IoC,它也应该有效(在 DryIoc 中验证)。 容器解析注入的参数,跳过可选参数:

var service = container.Resolve<MyWebService>();

示例代码

// <auto-generated />
public partial class MyWebService
{
    public MyWebService(object? dummyArgument = default)
        : this()
    {
        // Auto-generated constructor
    }
}

// Manually created
public partial class MyWebService
{
    protected MyWebService()
    {
    }
}

上面的适用于任意数量的构造函数参数。 至于虚拟参数,我们可以发明一种特殊类型(可能是枚举),进一步限制对这个额外参数的可能滥用。

A bit late to the game, but this is indeed possible. Kind of.

I recently performed the trick below in a code generator of mine, and the result is satisfying. Yes, a dummy argument is required, but it will not cause any major concerns. For consistency, you may want to apply some rules:

Rules

  1. Manually created constructor must be protected.
  2. Generated constructor must be public, with the same arguments as the protected one plus an extra optional dummy argument.
  3. The generated constructor calls the original constructor with all the supplied arguments.

This works for regular construction as well as reflection:

var s1 = new MyWebService();

var s2 = (MyWebService?)Activator.CreateInstance(
             typeof(MyWebService),
             BindingFlags.CreateInstance | BindingFlags.Public);

And for IoC, it should also work (verified in DryIoc). The container resolves the injected arguments, skipping the optional ones:

var service = container.Resolve<MyWebService>();

Sample code

// <auto-generated />
public partial class MyWebService
{
    public MyWebService(object? dummyArgument = default)
        : this()
    {
        // Auto-generated constructor
    }
}

// Manually created
public partial class MyWebService
{
    protected MyWebService()
    {
    }
}

The above works for any number of constructor arguments. As for the dummy arguments, we could invent a special type (maybe an enum) further restricting possible abuse of this extra argument.

揪着可爱 2024-07-15 18:48:00

我想不出什么。 我能想到的“最好”方法是添加一个带有虚拟参数的 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);

Nothing that I can think of. The "best" way I can come up with is to add a ctor with a dummy parameter and use that:

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文