Переопределить конструктор по умолчанию частичного класса другим частичным классом

StackOverflow https://stackoverflow.com/questions/247800

Вопрос

Я не думаю, что это возможно, но если да, то мне это нужно :)

У меня есть автоматически созданный прокси-файл с помощью инструмента командной строки 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...
      }
   }
}
Это было полезно?

Решение

Это невозможно. Частичные классы, по сути, являются частями одного класса; ни один метод не может быть определен дважды или переопределен, включая конструктор.

Вы можете вызвать метод в конструкторе и реализовать его только в другом файле детали.

Другие советы

У меня была похожая проблема: мой сгенерированный код был создан с помощью файла dbml (я использую классы Linq-to-SQL).

В сгенерированном классе он вызывает частичный void с именем OnCreated () в конце конструктора.

Короче говоря, если вы хотите сохранить важные вещи конструктора, которые сгенерированный класс делает для вас (что вы, вероятно, должны делать), то в своем частичном классе создайте следующее:

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

Хммм, я думаю, что одно элегантное решение было бы следующим:

//* 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. Неясно, когда именно будет выполнен конструктор внутреннего класса MyCustomization во время всей процедуры построения класса AutogenCls.

  2. Если потребуется реализовать интерфейс IDiposable для класса MyCustomization для правильной обработки удаления неуправляемых ресурсов класса MyCustomization, я не знаю (пока), как запустить метод MyCustomization.Dispose(), не затрагивая файл AutogenCls.cs ...(но как я уже сказал "пока" :)

Но этот подход обеспечивает отличное отделение от автоматически сгенерированного кода — вся настройка вынесена в отдельный файл кода src.

наслаждаться :)

На самом деле, это теперь возможно, теперь, когда были добавлены частичные методы. Вот документация:

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

Это несколько ограничено, и в данном конкретном случае, когда у вас есть сгенерированный файл, который вам нужно изменить, это может быть не правильным решением, но для тех, кто наткнулся на это, пытаясь переопределить функциональность в частичных классах это может быть очень полезно.

Проблема, с которой столкнулся OP, заключается в том, что веб-прокси-сервер не генерирует какие-либо частичные методы, которые можно использовать для перехвата конструктора.

Я столкнулся с той же проблемой и не могу просто перейти на 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.

Ты не можешь сделать это. Я предлагаю использовать частичный метод, для которого вы можете создать определение. Что-то вроде:

public partial class MyClass{ 

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

    public partial void OnCreated();
}

Остальное должно быть довольно понятным.

РЕДАКТИРОВАТЬ:

Я также хотел бы отметить, что вы должны определить интерфейс для этой службы, который затем можно запрограммировать, чтобы вам не нужно было ссылаться на фактическую реализацию. Если бы вы сделали это, у вас было бы несколько других вариантов.

Я думаю, вы можете сделать это с помощью PostSharp , и похоже, что кто-то только что что вы хотите использовать для методов в сгенерированных частичных классах . Я не знаю, будет ли это легко привести к возможности написать метод и заменить его тело на конструктор, так как я еще не попробовал, но, похоже, стоит попробовать.

Изменить: это в том же духе и также выглядит интересно.

Это, на мой взгляд, недостаток дизайна в языке. Они должны были позволить несколько реализаций одного частичного метода, который обеспечил бы хорошее решение. Еще более приятным способом конструктор (также метод) также может быть просто помечен как частичный, и при создании объекта будет запущено несколько конструкторов с одинаковой сигнатурой.

Самое простое решение, вероятно, состоит в том, чтобы добавить один частичный метод конструктора для каждого дополнительного частичного класса:

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

}

Но на самом деле им просто нужно добавить еще несколько языковых конструкций для работы с частичными классами.

Для прокси-сервера веб-службы, сгенерированного Visual Studio, вы не можете добавить свой собственный конструктор в частичный класс (что ж, вы можете, но он не вызывается). Вместо этого вы можете использовать атрибут [OnDeserialized] (или [OnDeserializing]), чтобы зацепить ваш собственный код в точке создания класса веб-прокси.

using System.Runtime.Serialization;

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

Иногда у вас нет доступа или вам не разрешено изменять конструктор по умолчанию, поэтому у вас не может быть конструктора по умолчанию для вызова каких-либо методов.

В этом случае вы можете создать другой конструктор с фиктивным параметром и заставить этот новый конструктор вызывать конструктор по умолчанию, используя " ;: this () "

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

И когда вы создаете новый экземпляр этого класса, вы просто передаете фиктивный параметр следующим образом:

SomeClass objSomeClass = new SomeClass(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);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top