Подтвердить что ты не робот

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

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

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

Ответ 1

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

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

Ответ 2

У меня был аналогичный пролет с созданным кодом, созданным файлом dbml (я использую классы Linq-to-SQL).

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

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

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

Ответ 3

Ммм, Я думаю, что одним из элегантных решений будет следующее:

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

Этот подход имеет некоторые недостатки (как и все):

  • Неясно, когда именно будет выполняться конструктор внутреннего класса MyCustomization во время всей процедуры построения класса AutogenCls.

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

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

наслаждайтесь:)

Ответ 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.
}

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

Ответ 5

Проблема, которую получил 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.

Ответ 6

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

public partial class MyClass{ 

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

    public partial void OnCreated();
}

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

ИЗМЕНИТЬ:

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

Ответ 7

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

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

Ответ 8

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

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

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

}

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

Ответ 9

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

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

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

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

SomeClass objSomeClass = new SomeClass(0);

Ответ 10

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

using System.Runtime.Serialization;

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

Ответ 11

Я не совсем обращаюсь к OP, но если вы генерируете классы с помощью обратного генератора POCO EntityFramework, в конструкторе вызывается частичный метод, который удобен для инициализации вещей, которые вы добавляете через частичные классы самостоятельно..

Сгенерировано инструментом:

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

Ответ 12

Ничего, о чем я могу думать. "Самый лучший" способ, который я могу придумать, - добавить 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);