Apelarea constructorului de bază în C #

Dacă am moștenit dintr-o clasă de bază și vreau să trec ceva de la constructorul clasei moștenite la constructorul clasei de bază, cum să fac asta?

De exemplu,

Dacă am moștenit din clasa Excepție vreau să fac ceva de genul:

class MyExceptionClass : Exception
{
     public MyExceptionClass(string message, string extraInfo)
     {
         //This is where it's all falling apart
         base(message);
     }
}

În principiu, ceea ce vreau este să pot transmite mesajul șir la clasa de excepție de bază.

0
fr hi bn
De asemenea, merită remarcat că puteți constructorii de lanț din clasa curentă înlocuind acest pentru base .
adăugat autor Quibblesome, sursa

10 răspunsuri

Modificați-vă constructorul astfel încât acesta să sune corect constructorul de bază:

public class MyExceptionClass : Exception
{
    public MyExceptionClass(string message, string extrainfo) : base(message)
    {
        //other stuff here
    }
}

Rețineți că un constructor nu este ceva pe care îl puteți apela oricând într-o metodă. Acesta este motivul pentru care primiți erori în apelul dvs. în corpul constructorului.

0
adăugat
Dacă trebuie să apelați constructorul de bază în mijlocul suprascrierii, extrageți-l într-o metodă reală din clasa de bază pe care o puteți apela în mod explicit. Presupunerea cu constructorii de bază este că aceștia sunt absolut necesari pentru a crea în siguranță un obiect, astfel că baza va fi numită mai întâi, întotdeauna.
adăugat autor Jon Limjap, sursa
@Sebastien Da și nu. Dacă constructorul dvs. acționează ca metodă de șablon care apelează alte operații primitive (metode abstracte), atunci este posibil să o implementați. Orice altă implementare care trebuie să apeleze explicit un constructor dintr-o altă metodă sau o altă suprascriere a constructorului este ceea ce este interzis.
adăugat autor Jon Limjap, sursa
Este este doar o metodă pe care o puteți apela în orice moment, IL-înțelept. C# se întâmplă doar să pună restricții suplimentare în partea de sus a acestui lucru.
adăugat autor Roman Starkov, sursa
Este de remarcat faptul că constructorul base se numește înainte ca să se acceseze blocul de metode. msdn.microsoft.com/en-us/library/ms173115.aspx
adăugat autor John Weisz, sursa
Nu este un design bun dacă trebuie să apelați constructorul de clasă de bază la jumătatea distanței în timpul constructorului. Ideea unui constructor este că face tot munca necesară pentru a-și îndeplini sarcinile. Acest lucru are ca efect faptul că atunci când constructorul dvs. derivat începe, clasa de bază este deja pe deplin inițializată, iar clasa derivată este liberă să apeleze orice funcție de clasă de bază. Dacă designul dvs. este de așa natură încât doriți să faceți ceva pe jumătate constructorul dvs., atunci aparent acest lucru nu iniționează clasa de bază și astfel nu ar trebui să f
adăugat autor Harald Coppoolse, sursa
Cred că ați pierdut punctul. Problema a fost aceea de a apela un constructor de bază la jumătatea distanței prin constructorul suprascris. Poate că tipul de date al constructorului de bază nu este același sau vreți să efectuați o prelucrare a datelor înainte de al trece în lanț. Cum ai realiza o astfel de faptă?
adăugat autor Marchy, sursa
@romkyns Pentru o clasă, da. Pentru un struct, nu. C# nu vă permite să apelați un constructor de bază pentru structuri pentru a vă asigura că rămân (în felul) sănătoși și pentru clase pentru a păstra lucrurile la fel peste tot. (Comparați cu C ++, unde același lucru este adevărat, cu excepția faptului că alegerea stocată pe stack sau pe heap este făcută în codul de apel, mai degrabă decât în ​​codul de clasă și aceeași limitare este în vigoare)
adăugat autor Jasper, sursa
@JonLimjap înseamnă că nu puteți implementa modelul metodei șablon cu un constructor?
adăugat autor Sebastien, sursa
class Exception
{
     public Exception(string message)
     {
         [...]
     }
}

class MyExceptionClass : Exception
{
     public MyExceptionClass(string message, string extraInfo)
     : base(message)
     {
         [...]
     }
}
0
adăugat

Dacă trebuie să sunați la constructorul de bază, dar nu imediat, deoarece noua dvs. clasă (derivată) trebuie să facă unele manipulări de date, cea mai bună soluție este să recurgeți la metoda din fabrică. Ceea ce trebuie să faceți este să marcați constructorul derivat privat, apoi să faceți o metodă statică în clasa dvs., care va face toate lucrurile necesare și apoi va apela constructorul și va returna obiectul.

public class MyClass : BaseClass
{
    private MyClass(string someString) : base(someString)
    {
        //your code goes in here
    }

    public static MyClass FactoryMethod(string someString)
    {
        //whatever you want to do with your string before passing it in
        return new MyClass(someString);
    }
}
0
adăugat
Acest lucru ar putea potențialul să încalce principiile SOLID (SRP), deoarece responsabilitatea creării clasei este încapsulată cu orice alte responsabilități pe care le presupune că clasa trebuie să o aibă. O fabrică abstractă ar putea fi utilizată, dar ar putea adăuga complexitate inutilă codului simplu. Bineinteles, incalcarea SOLID-urilor este ok daca stii ce tradeoff si taxa pe care o vei pune pe arhitectura ta (si cum poti rezolva orice problema viitoare care ar putea aparea din decizia ta de design).
adăugat autor Sebastien, sursa

Rețineți că puteți utiliza metode statice în timpul apelului către constructorul de bază.

class MyExceptionClass : Exception
{
     public MyExceptionClass(string message, string extraInfo) : 
         base(ModifyMessage(message, extraInfo))
     {
     }

     private static string ModifyMessage(string message, string extraInfo)
     {
         Trace.WriteLine("message was " + message);
         return message.ToLowerInvariant() + Environment.NewLine + extraInfo;
     }
}
0
adăugat
Ne pare rău, C# newb aici. De ce apelați Trace.WriteLine ("mesajul a fost" + message) ?
adăugat autor kdbanman, sursa
Nu există absolut nimic rău în această privință, atâta timp cât funcția intermediară este statală morală. Logarea nu este un caz bun de utilizare, IMO, dar normalizarea carcasei sau adăugarea suplimentară pare bine.
adăugat autor Aluan Haddad, sursa
@kdbanman Asta trimite doar un mesaj de depanare. Nu există un scop funcțional relevant.
adăugat autor Nick Whaley, sursa
Acest lucru nu pare foarte solid (dacă știți ce vreau să spun) (... SRP ...)
adăugat autor Sebastien, sursa
Clasa Excepție este atât de blocată, încât mă găsesc eu de două ori, dar notăm că nu ar trebui să faci ceva dacă o poți evita.
adăugat autor SMASH, sursa
Bună @ChrisS, pot folosi ca `: base (" Mesajul meu implicit. ")`, Cum se utilizează astfel?
adăugat autor Carlos, sursa
Mare răspuns. Răspunsul acceptat nu îmi permite să fac procesarea; și Comentariul de urmărire a unei soluții presupune că am acces la schimbați clasa de bază; Eu nu. Un răspuns din fabrică presupune că pot controla modul în care clasa este instanțiată; Nu pot. Numai răspunsul vă permite să modificați ceva înainte de al trece pe baza.
adăugat autor The Red Pea, sursa
Mulțumesc atât de mult pentru asta, trebuia să creez un context de bază de date cu folosind pentru a prelua o valoare pentru a trece la constructorul de bază și nu aveam idee cum să fac asta.
adăugat autor Micheal Johnson, sursa

De asemenea, puteți face o verificare condiționată și puteți transmite proprietăți în constructsau, ceea ce permite o anumită flexibilitate.

public MyClass(object myObject=null): base(myObject ?? new myOtherObject())
{
}

sau

public MyClass(object myObject=null): base(myObject==null ? new myOtherObject(): myObject)
{
}
0
adăugat
Nu trebuie să eliminați cuvântul "clasă" din exemplul dvs., deoarece aceștia sunt constructori ...
adăugat autor MarzSocks, sursa

From Framewsauk Design Guidelines and FxCop rules.:

1. Excepția personalizată ar trebui să aibă un nume care se termină cu excepția

    class MyException : Exception

2. Excepția ar trebui să fie publică

    public class MyException : Exception

3. CA1032: Excepția ar trebui să implementeze constructsauii standard.

  • A public parameterless constructsau.
  • A public constructsau with one string argument.
  • A public constructsau with one string and Exception (as it can wrap another Exception).
  • A serialization constructsau protected if the type is not sealed and private if the type is sealed. Based on MSDN:

    [Serializable()]
    public class MyException : Exception
    {
      public MyException()
      {
        //Add any type-specific logic, and supply the default message.
      }
    
      public MyException(string message): base(message) 
      {
        //Add any type-specific logic.
      }
      public MyException(string message, Exception innerException): 
         base (message, innerException)
      {
        //Add any type-specific logic fsau inner exceptions.
      }
      protected MyException(SerializationInfo info, 
         StreamingContext context) : base(info, context)
      {
        //Implement type-specific serialization constructsau logic.
      }
    }  
    

sau

    [Serializable()]
    public sealed class MyException : Exception
    {
      public MyException()
      {
        //Add any type-specific logic, and supply the default message.
      }

      public MyException(string message): base(message) 
      {
        //Add any type-specific logic.
      }
      public MyException(string message, Exception innerException): 
         base (message, innerException)
      {
        //Add any type-specific logic fsau inner exceptions.
      }
      private MyException(SerializationInfo info, 
         StreamingContext context) : base(info, context)
      {
        //Implement type-specific serialization constructsau logic.
      }
    }  
0
adăugat
public class MyExceptionClass : Exception
{
    public MyExceptionClass(string message,
      Exception innerException): base(message, innerException)
    {
        //other stuff here
    }
}

Puteți trece excepția internă la unul dintre constructori.

0
adăugat

Este adevărat să folosiți base (ceva) pentru a apela constructorul de clasă de bază, dar în caz de supraîncărcare folosiți cuvântul cheie this

public ClassName() : this(par1,par2)
{
// do not call the constructor it is called in the this.
// the base key- word is used to call a inherited constructor   
} 

// Hint used overload as often as needed do not write the same code 2 or more times
0
adăugat
Vad ce vrei să explici și ai dreptate. Dacă aveți doi constructori dintr-o clasă, puteți să vă referiți unul la celălalt utilizând cuvântul cheie "acest", similar cu modul în care utilizați "bază" atunci când sunați constructorul moștenit. Cu toate acestea, nu este ceea ce a cerut PO, astfel încât acesta nu este cu adevărat locul în care să se adauge acest lucru.
adăugat autor IAmTimCorey, sursa
public class MyException : Exception
{
    public MyException() { }
    public MyException(string msg) : base(msg) { }
    public MyException(string msg, Exception inner) : base(msg, inner) { }
}
0
adăugat

În conformitate cu unele dintre celelalte răspunsuri enumerate aici, puteți trece parametrii în constructorul de clasă de bază. Este recomandat să apelați constructorul de clasă de bază la începutul constructorului pentru clasa moștenită.

public class MyException : Exception
{
    public MyException(string message, string extraInfo) : base(message)
    {
        this.Message = $"{message} Extra info: {extraInfo}";
       //You can omit the 'this.' portion above...
    }
}

Am observat că în exemplul dvs. nu ați utilizat niciodată parametrul extraInfo , așa că am presupus că ați putea concatenarea parametrului extraInfo șir la Message proprietatea excepției dvs. (se pare că acest lucru este ignorat în răspunsul acceptat și în codul din întrebarea dvs.).

Acest lucru este realizat pur și simplu prin invocarea constructorului de clasă de bază și apoi prin actualizarea proprietății mesajului cu informațiile suplimentare.

Ca alternativă, deoarece proprietatea Message este moștenită de la clasa de bază, nici măcar nu trebuie să apelați explicit constructorul clasei de bază. Puteți doar să actualizați proprietatea Message direct de la constructorul clasei dvs. moștenite, după cum urmează:

public class MyException : Exception
{
    public MyException(string message, string extraInfo)
    {
        this.Message = $"{message} Extra info: {extraInfo}";
       //You can omit the 'this.' portion above...
    }
}
0
adăugat