2016-04-26 5 views
2

Warum ist, wenn ich ein schattiertes Feld in einem Basisklassenkonstruktor festgelegt (unter Verwendung new Schlüsselwort deklariert) das Feld Shadowed festgelegt wird, aber nicht das Feld Shadowing?Shadowed-Feld wird nicht in Basisklassenkonstruktor

Ich dachte, dass this.GetType() bezogen auf die äußerste Klasse den ganzen Weg hinunter in Basisklassenaufrufe einschließlich des Konstruktors. Ich dachte auch, dass Shadowing das Schattenfeld nicht zugänglich machte.

In meiner schnellen Wache kann ich zwei Felder sehen, das beschattete, das gesetzt wurde, und das Schattenbild (der Unterklasse), das noch nicht initialisiert ist.

Ich habe es behoben, indem ich das Schattenfeld im Unterklassenkonstruktor explizit gesetzt habe, nachdem es den Basisklassenkonstruktor aufgerufen hat, aber ich würde trotzdem gerne wissen, warum es so funktioniert. .Net Fiddle

using System; 

public class Program 
{ 
    public static void Main() 
    { 
     SubClass subClass = new SubClass(2); 
     Console.WriteLine(subClass.MyField); 
    } 
} 

public class BaseClass 
{ 
    public BaseClass(int value) 
    { 
     MyField = value; // This doesn't point to SubClass.MyField 
    } 

    public int MyField; 
} 

public class SubClass : BaseClass 
{ 
    public SubClass(int value):base(value) 
    { 

    } 

    public new int MyField = 4; 

} 

aktualisieren

Nach Antworten bewerten, ich sehe ich nicht fragen, was ich in der direkteste Weg, wissen wollte. Entschuldigung für jegliche Unannehmlichkeiten. Hier ist, was ich wirklich wissen möchte:

Ich verstehe Shadowing. Ich stimme damit nicht überein. Ich denke nicht, dass es für Felder erlaubt sein sollte (solange übersteuerbare Felder zu einem Sprachmerkmal gemacht wurden). Ich sehe den Punkt in den Schattenfeldern nicht und habe das schattierte Feld, das herumhängt. Ich sehe jedoch den Punkt in überschreibbaren Feldern und ich verstehe nicht, warum dieses Sprachfeature nicht existiert, wenn es für Eigenschaften und Methoden existiert. Warum also auf Feldern Schatten werfen? Warum gibt es keinen Vorrang vor Feldern?

+1

Es wäre viel einfacher, Ihnen zu helfen, wenn Sie den Code * zeigen * anstatt ihn * zu beschreiben. Grundsätzlich sind Felder nicht polymorph - der Basisklassenkonstruktor kennt nur das Basisklassenfeld und kann nur lesen/schreiben. Ich vermute, das erklärt alles, was du siehst, aber es ist schwer zu sagen, nur aus deiner Beschreibung. –

+1

"Ich dachte auch, dass Shadowing das Schattenfeld nicht existierte." Ich weiß nicht, was du damit meinst oder wo du diese Idee hast. –

+4

@JonSkeet, ok Ich werde etwas Code hinzufügen. Ich meinte, dass das Schattenfeld unzugänglich war, weil es abgelöst wurde; effektiv in der Unterklasse neu deklariert. Ihr Ruf ist 861k; mein Argument ist ungültig :-) – toddmo

Antwort

7

Wir haben

Ich dachte auch, dass Abschattung der schraffierte Bereich nicht zugänglich gemacht werden.

von

Gefolgt ich Abschattung verstehen tun.

Ich bin mir nicht ganz sicher, dass Sie das tun. Du hast bereits eine falsche Meinung über das Shadowing geäußert. Woher wissen wir, dass es nicht mehr gibt?

Ich stimme nicht mit ihm.

Ihre Meinung wird zur Kenntnis genommen. Ich stelle fest, dass Sie das Feature nicht verwenden müssen, wenn Sie es nicht mögen.

Ich glaube nicht, dass es für Felder zulässig sein sollte (solange übersteuerbare Felder ein Sprachfeature gemacht wurden).

zur Kenntnis genommen.

Ich sehe jedoch den Punkt in überschreibbaren Feldern und ich verstehe nicht, warum dieses Sprachfeature nicht existiert, wenn es für Eigenschaften und Methoden existiert.

Felder sollten private Implementierungsdetails von Klassen sein. Wenn dies der Fall ist, dann gibt es keinen zugänglichen Namen zum Beschatten oder Überschreiben, also ist das Problem strittig. Eine Funktion, die niemandem zur Verfügung stehen soll, ist eine schlechte Funktion.

Warum also Shadowing auf Feldern?

Angenommen, es gibt ein geschütztes Feld in einer abgeleiteten Klasse. Betrachten Sie nun das Problem der Versprödungsklasse. Bearbeiten Sie eine Reihe solcher Szenarien; Sie die Sprache Design Wahl der kritischen Beurteilung, denken so wie die Sprache Designer denken. Was folgern Sie aus Ihrer Untersuchung typischer Sprödbasisklassen-Szenarien?

Warum überschreiben Felder nicht?

Weil (1) wir keinen Mechanismus für das Überschreiben von Feldern haben; Methoden haben vtables, aber es gibt keinen vtable-Mechanismus für Felder. Und (2) Felder sollten private Details der Implementierung von Klassen sein, und daher gibt es nie eine Notwendigkeit, sie außer Kraft zu setzen. Wenn Sie ein Feld überschreiben möchten, erstellen Sie eine Eigenschaft, die es umschließt und überschreibt. Die Codeänderung ist winzigen von einem Feld zu einem virtuellen Objekt zu gehen.

Felder sollten in der Mechanism Domain der Klasse sein; Eigenschaften befinden sich in der Geschäftsdomäne. Spezialisierung des Verhaltens gehört in die Geschäftsdomäne.

0

nicht sicher, warum Sie dies tun wollen, aber hier ist wie:

public class BaseClass 
{ 
    public BaseClass(int value) 
    { 
     SetValue(x => x.MyField, value); 
    } 

    public int MyField; 

    public void SetValue<TField>(Expression<Func<BaseClass, TField>> memberSelector, TField value) 
    { 
     var expression = memberSelector.Body as MemberExpression; 
     if (expression == null) 
      throw new MemberAccessException(); 

     this.GetType().GetField(expression.Member.Name) 
      .SetValue(this, value); 
    } 
} 
+0

Ich habe meine Frage aktualisiert, um zu verdeutlichen, was ich hier wirklich frage. Entschuldigung für jegliche Unannehmlichkeiten. Ich wollte die Rollen von Basis- und Unterklasse nicht umkehren, wie Sie es hier tun. Ich wusste einfach nicht, warum der Code der Unterklasse meine Erwartungen nicht erfüllt hat. – toddmo

+0

Bitte ändere deine Frage nicht drastisch, wenn sie bereits einige Antworten (+ eine akzeptierte) hat und wenn eine Stunde bereits verstrichen ist. Nachdem das gesagt wurde, ist Ihre Frage Post doppelt. Siehe: http://programmers.stackexchange.com/questions/153738/what-are-some-practical-uses-of-the-new-modifier-in-c-mith-respect-to-hiding – Xiaoy312

+0

Ich lese gerade es! Vielen Dank! – toddmo

0

Denken Sie daran, die ein Feld Shadowing macht gerade ein neues Feld, ist es in keiner Weise auf das Feld in der Basis bezogenen Klasse (außer aufgrund der Tatsache, dass Sie es den gleichen Namen gegeben haben).

Einfach gesagt, Sie haben keinen Code geschrieben, der das Feld in SubClass setzt, haben Sie nur geschriebenen Code, der das Feld in BaseClass setzt:

public class BaseClass 
{ 
    public BaseClass(int value) 
    { 
     MyField = value; // This doesn't point to SubClass.MyField 
    } 

    public int MyField; 
} 

MyField hier kann sich immer nur auf das beziehen MyField in BaseClass. Es kann unmöglich wissen, dass Sie später eine Unterklasse erstellen und ein Feld mit demselben Namen einfügen. Und selbst wenn Sie das tun, haben Sie nur ein anderes Feld mit dem gleichen Namen erstellt, also warum sollte BaseClass.MyField auch die meist nicht verwandte SubClass.MyField setzen?

2
public class BaseClass 
{ 
    public BaseClass(int value) 
    { 
     MyField = value; // This doesn't point to SubClass.MyField 
    } 

    public int MyField; 
} 

Die Basisklasse über seine abgeleiteten Typen nicht kennt. MyField = value macht genau das, was es sagt: es weist MyField mit value zu.

public class SubClass : BaseClass 
{ 
    public SubClass(int value):base(value) 
    { 

    } 

    public new int MyField = 4; 

} 

Erwarten Sie den Wert 4 in den Basistyp zu propagieren?Ihre Frage ist ziemlich schwer zu beantworten, weil es nicht genau klar ist, was Ihre Definition von "intuitiv" und Erwartungen sind .... und Ihr Beispiel-Code ist sehr schlecht OOP-Design.

Es gibt nicht viele gute Gründe, jemals ein public Feld, Basisklasse oder nicht, freizugeben.

Lassen Sie mich Ihr Beispiel umformulieren:

public abstract class BaseClass 
{ 
    protected BaseClass(int value) 
    { 
     _value = value; 
    } 

    private int _value; 
    public virtual int Value { get { return _value; } set { _value = value; } } 
} 

public class SubClass : BaseClass 
{ 
    public SubClass(int value) : base(value) 
    { 

    } 

    public new int Value { get; set; } // hides base class member 
} 

Jetzt. SubClass.Value ist eine eigene Sache - wenn Sie auf den Wert zugreifen möchten, der über den Konstruktor übergeben wurde, müssen Sie dies über die Basisklasse tun.

Die Basisklasse Mitglied nicht „aufhören zu existieren“, es ist nur versteckt, oder beschatteten, durch ein neues Mitglied in einem abgeleiteten Typ, dass nur so geschieht die gleiche Kennung hat:

var foo = new SubClass(42); 
Console.WriteLine(foo.Value); 
Console.WriteLine(((BaseClass)foo).Value); 

Console.ReadKey(); 

Dieser Code gibt 0, dann 42 - denn wenn foo.Value die zugegriffen wird SubClass sagt: „hey Basisklasse, lassen Sie mich das machen. - ich meine eigene Definition von Value haben, und dieser Ruf Mine holen“ ... und gibt 0 zurück, weil es eigentlich nie zugewiesen wurde; Die 42 ist nur über die Basisklasse sichtbar.

Das ist was Mitglied Shadowing tut.

Und es funktioniert auf das gleiche auch ohne new Stichwort - das new Schlüsselwort nur unterdrückt eine Compiler-Warnung, die sagt: „Sie eine Basisklasse Mitglied versteckt sind hier, sind Sie wirklich ganz ganz sicher, dass Sie beabsichtigen, dies zu tun? "- denn in einer normalen Welt ist das normalerweise nicht das, was Sie tun möchten.

Nun, ich habe die Value Eigenschaft virtual gemacht. Was passiert, wenn Sie stattdessen override?

public class SubClass : BaseClass 
{ 
    public SubClass(int value) 
     : base(value) 
    { 

    } 

    public override int Value { get; set; } 
} 

Das kleine Konsolenprogramm über (ein paar Schnipsel oben) gibt nun 0 und 0 - weil die Unterklasse Valueüberschreibt die Basisklasse Mitglied, effektiv C# sagen, Mitglied zu lösen, um den abgeleiteten Typ aufruft. So geben Sie die 42 Sie übergeben, , weil Sie das Mitglied überschreiben, werden Sie verantwortlich dafür, wie es funktioniert - das _value private Feld in der Basisklasse sagt immer noch 42, aber die Value Eigenschaft wird überschrieben, das Feld bleibt ungenutzt.

So ordnen Sie es in Ihrem Konstruktor der abgeleiteten Typ (hier die Klasse Abdichten eines virtuellen Mitglied Aufruf im Konstruktor zu vermeiden):

public sealed class SubClass : BaseClass 
{ 
    public SubClass(int value) 
     : base(0) 
    { 
     Value = value; 
    } 

    public override int Value { get; set; } 
} 

So, hier die abgeleiteten Typ 0 auf die Basisklasse ist vorbei, und überschreibe das Mitglied. Was gibt der kleine Ausschnitt für 42 jetzt aus?

static void Main(string[] args) 
    { 
     var foo = new SubClass(42); 
     Console.WriteLine(foo.Value); 
     Console.WriteLine(((BaseClass)foo).Value); 

     Console.ReadKey(); 
    } 

gibt er 42 sowohl für die abgeleiteten und die downcasted Anrufe, weil die Art Guss nun überflüssig ist, da das virtuelle Mitglied außer Kraft gesetzt wird.

Verwandte Themen