Was unterscheidet ein Feld in C # von einer Eigenschaft und wann sollte ein Feld anstelle einer Eigenschaft verwendet werden?
Was unterscheidet ein Feld in C # von einer Eigenschaft und wann sollte ein Feld anstelle einer Eigenschaft verwendet werden?
Antworten:
Eigenschaften machen Felder verfügbar. Felder sollten (fast immer) für eine Klasse privat gehalten und über get- und set-Eigenschaften aufgerufen werden. Eigenschaften bieten eine Abstraktionsebene, mit der Sie die Felder ändern können, ohne die externe Art und Weise zu beeinflussen, auf die die Benutzer Ihrer Klasse auf sie zugreifen.
public class MyClass
{
// this is a field. It is private to your class and stores the actual data.
private string _myField;
// this is a property. When accessed it uses the underlying field,
// but only exposes the contract, which will not be affected by the underlying field
public string MyProperty
{
get
{
return _myField;
}
set
{
_myField = value;
}
}
// This is an AutoProperty (C# 3.0 and higher) - which is a shorthand syntax
// used to generate a private field for you
public int AnotherProperty{get;set;}
}
@Kent weist darauf hin, dass Eigenschaften nicht zum Einkapseln von Feldern erforderlich sind, sondern eine Berechnung für andere Felder durchführen oder anderen Zwecken dienen können.
@GSS weist darauf hin, dass Sie beim Zugriff auf eine Eigenschaft auch andere Logik ausführen können, z. B. die Validierung. Dies ist eine weitere nützliche Funktion.
string
, lautet mein Vertrag: Weisen Sie Zeichen mit einer Länge von bis zu ~ 2bil zu. Wenn es sich um eine Immobilie handelt DateTime
, lautet mein Vertrag: Weisen Sie innerhalb der Grenzen von DateTime beliebige Nummern zu, die ich nachschlagen kann. Wenn der Ersteller den Setzern Einschränkungen hinzufügt, werden diese Einschränkungen nicht kommuniziert. Wenn der Ersteller stattdessen den Typ von string
in ändert Surname
, kommuniziert die neue Nachnamenklasse die Einschränkungen, und die Eigenschaft public Surname LastName
verfügt nicht über eine Setter-Validierung. Ist auch Surname
wiederverwendbar.
Surname
in meinem Beispiel wiederverwendbar ist, müssen Sie sich später keine Gedanken mehr darüber machen, wie Sie diese Überprüfungen in einem Eigenschaftssetter an andere Stellen im Code kopieren / einfügen. Sie fragen sich auch nicht, ob die Validierung eines Nachnamens an mehreren Stellen erfolgt, wenn Sie jemals Änderungen an den Geschäftsregeln für Nachnamen vornehmen. Schauen Sie sich den Link an, den ich über Value Objects
Objektorientierte Programmierprinzipien besagen, dass die internen Abläufe einer Klasse vor der Außenwelt verborgen sein sollten. Wenn Sie ein Feld verfügbar machen, legen Sie im Wesentlichen die interne Implementierung der Klasse offen. Daher umschließen wir Felder mit Eigenschaften (oder Methoden in Javas Fall), um die Implementierung zu ändern, ohne den Code abhängig von uns zu beschädigen. Da wir Logik in die Eigenschaft einfügen können, können wir auch Validierungslogik usw. ausführen, wenn wir sie benötigen. C # 3 hat die möglicherweise verwirrende Vorstellung von Autoproperties. Auf diese Weise können wir einfach die Eigenschaft definieren und der C # 3-Compiler generiert das private Feld für uns.
public class Person
{
private string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
public int Age{get;set;} //AutoProperty generates private field for us
}
public int myVar { get; set; }
wirklich steht (und ich nehme an, dass es der Grund ist für mindestens 50% der Treffer erhält diese Frage).
virtual
selbst Teil der objektorientierten Programmierung.
virtual
OOP jedoch nicht per se anrufen . Es ist ein Werkzeug, das Polymorphismus ermöglicht. Dies ist eines der Schlüsselwerkzeuge, die OOP AKTIVIEREN. Es ist jedoch nicht OOP an und für sich, und an einer öffentlichen Autoproperty ist nichts von Natur aus OOP. Ich würde auch Dinge wie Reflection oder OOP im Zusammenhang mit der Datenbindung nicht zählen. Normalerweise wäre ich nicht so pedantisch, aber in der Antwort wurden speziell die OO-Prinzipien als treibende Kraft hinter dem Codebeispiel genannt, und dem stimme ich nicht zu.
Ein wichtiger Unterschied besteht darin, dass Schnittstellen Eigenschaften haben können, jedoch keine Felder. Dies unterstreicht für mich, dass Eigenschaften verwendet werden sollten, um die öffentliche Schnittstelle einer Klasse zu definieren, während Felder für die privaten, internen Abläufe einer Klasse verwendet werden sollen. In der Regel erstelle ich selten öffentliche Felder und in ähnlicher Weise auch nicht öffentliche Eigenschaften.
Ich gebe Ihnen ein paar Beispiele für die Verwendung von Eigenschaften, die die Zahnräder zum Drehen bringen könnten:
Mit Eigenschaften können Sie ein Ereignis auslösen, wenn der Wert der Eigenschaft geändert wird (auch bekannt als PropertyChangedEvent) oder bevor der Wert geändert wird, um die Stornierung zu unterstützen.
Dies ist mit (direktem Zugriff auf) Feldern nicht möglich.
public class Person {
private string _name;
public event EventHandler NameChanging;
public event EventHandler NameChanged;
public string Name{
get
{
return _name;
}
set
{
OnNameChanging();
_name = value;
OnNameChanged();
}
}
private void OnNameChanging(){
NameChanging?.Invoke(this,EventArgs.Empty);
}
private void OnNameChanged(){
NameChanged?.Invoke(this,EventArgs.Empty);
}
}
Da viele von ihnen mit technischen Vor- und Nachteilen von Properties
und erklärt haben Field
, ist es Zeit, sich mit Beispielen in Echtzeit zu befassen.
1. Mit Eigenschaften können Sie die schreibgeschützte Zugriffsebene festlegen
Betrachten Sie den Fall von dataTable.Rows.Count
und dataTable.Columns[i].Caption
. Sie kommen aus der Klasse DataTable
und beide sind für uns öffentlich. Der Unterschied in der Zugriffsebene besteht darin, dass wir keinen Wert festlegen können, dataTable.Rows.Count
aber lesen und schreiben können dataTable.Columns[i].Caption
. Ist das möglich durch Field
? Nein!!! Dies ist nur mit möglich Properties
.
public class DataTable
{
public class Rows
{
private string _count;
// This Count will be accessable to us but have used only "get" ie, readonly
public int Count
{
get
{
return _count;
}
}
}
public class Columns
{
private string _caption;
// Used both "get" and "set" ie, readable and writable
public string Caption
{
get
{
return _caption;
}
set
{
_caption = value;
}
}
}
}
2. Eigenschaften in PropertyGrid
Möglicherweise haben Sie Button
in Visual Studio mit gearbeitet. Seine Eigenschaften sind in der gezeigt PropertyGrid
wie Text
, Name
usw. Wenn wir ziehen und einen Knopf fallen, und wenn wir die Eigenschaften klicken, wird es automatisch die Klasse finden Button
und Filter Properties
und zeigen , dass in PropertyGrid
(wo PropertyGrid
zeigen nicht , Field
auch wenn sie öffentlich sind).
public class Button
{
private string _text;
private string _name;
private string _someProperty;
public string Text
{
get
{
return _text;
}
set
{
_text = value;
}
}
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
[Browsable(false)]
public string SomeProperty
{
get
{
return _someProperty;
}
set
{
_someProperty= value;
}
}
In PropertyGrid
werden die Eigenschaften Name
und Text
angezeigt, aber nicht SomeProperty
. Warum??? Weil Eigenschaften Attribute akzeptieren können . Es wird nicht angezeigt, wenn [Browsable(false)]
es falsch ist.
3. Kann Anweisungen in Eigenschaften ausführen
public class Rows
{
private string _count;
public int Count
{
get
{
return CalculateNoOfRows();
}
}
public int CalculateNoOfRows()
{
// Calculation here and finally set the value to _count
return _count;
}
}
4. In der Bindungsquelle können nur Eigenschaften verwendet werden
Mit Binding Source können wir die Anzahl der Codezeilen verringern. Fields
werden von nicht akzeptiert BindingSource
. Wir sollten dafür verwenden Properties
.
5. Debugging-Modus
Stellen Sie sich vor, wir verwenden Field
, um einen Wert zu halten. Irgendwann müssen wir debuggen und überprüfen, wo der Wert für dieses Feld null wird. Es wird schwierig sein, wenn die Anzahl der Codezeilen mehr als 1000 beträgt. In solchen Situationen können wir Property
den Debug-Modus verwenden und festlegen Property
.
public string Name
{
// Can set debug mode inside get or set
get
{
return _name;
}
set
{
_name = value;
}
}
Ein Feld ist eine Variable, die direkt in einer Klasse oder Struktur deklariert wird. Eine Klasse oder Struktur kann Instanzfelder oder statische Felder oder beides haben. Im Allgemeinen sollten Sie Felder nur für Variablen verwenden, die einen privaten oder geschützten Zugriff haben . Daten, die Ihre Klasse für Clientcode verfügbar macht, sollten über Methoden, Eigenschaften und Indexer bereitgestellt werden. Durch die Verwendung dieser Konstrukte für den indirekten Zugriff auf interne Felder können Sie sich vor ungültigen Eingabewerten schützen.
Eine Eigenschaft ist ein Mitglied, das einen flexiblen Mechanismus zum Lesen, Schreiben oder Berechnen des Werts eines privaten Felds bietet. Eigenschaften können so verwendet werden, als wären sie öffentliche Datenelemente, aber es handelt sich tatsächlich um spezielle Methoden, die als Accessoren bezeichnet werden . Dies ermöglicht den einfachen Zugriff auf Daten und fördert dennoch die Sicherheit und Flexibilität der Methoden . Mithilfe von Eigenschaften kann eine Klasse eine öffentliche Methode zum Abrufen und Festlegen von Werten verfügbar machen, während Implementierungs- oder Überprüfungscode ausgeblendet wird. Ein get-Eigenschafts-Accessor wird verwendet, um den Eigenschaftswert zurückzugeben, und ein festgelegter Accessor wird verwendet, um einen neuen Wert zuzuweisen.
Eigenschaften haben den Hauptvorteil, dass Sie die Art und Weise ändern können, in der auf Daten eines Objekts zugegriffen wird, ohne die öffentliche Schnittstelle zu beschädigen. Wenn Sie beispielsweise eine zusätzliche Validierung hinzufügen oder ein gespeichertes Feld in ein berechnetes Feld ändern müssen, können Sie dies problemlos tun, wenn Sie das Feld ursprünglich als Eigenschaft verfügbar gemacht haben. Wenn Sie nur ein Feld direkt verfügbar gemacht haben, müssen Sie die öffentliche Schnittstelle Ihrer Klasse ändern, um die neue Funktionalität hinzuzufügen. Diese Änderung würde bestehende Clients beschädigen und eine Neukompilierung erfordern, bevor sie die neue Version Ihres Codes verwenden können.
Wenn Sie eine Klassenbibliothek schreiben, die für einen breiten Verbrauch ausgelegt ist (wie das .NET Framework, das von Millionen von Menschen verwendet wird), kann dies ein Problem sein. Wenn Sie jedoch eine Klasse schreiben, die intern in einer kleinen Codebasis verwendet wird (z. B. <= 50 K Zeilen), ist dies keine große Sache, da niemand durch Ihre Änderungen beeinträchtigt würde. In diesem Fall kommt es wirklich nur auf die persönlichen Vorlieben an.
Die Eigenschaften unterstützen den asymmetrischen Zugriff, dh Sie können entweder einen Getter und einen Setter oder nur einen der beiden haben. In ähnlicher Weise unterstützen Eigenschaften die individuelle Zugänglichkeit für Getter / Setter. Felder sind immer symmetrisch, dh Sie können den Wert immer sowohl abrufen als auch einstellen. Eine Ausnahme bilden schreibgeschützte Felder, die nach der Initialisierung offensichtlich nicht gesetzt werden können.
Eigenschaften können sehr lange laufen, Nebenwirkungen haben und sogar Ausnahmen auslösen. Felder sind schnell, ohne Nebenwirkungen und werden niemals Ausnahmen auslösen. Aufgrund von Nebenwirkungen kann eine Eigenschaft für jeden Aufruf einen anderen Wert zurückgeben (wie dies bei DateTime.Now der Fall sein kann, dh DateTime.Now ist nicht immer gleich DateTime.Now). Felder geben immer den gleichen Wert zurück.
Felder können für out / ref-Parameter verwendet werden, Eigenschaften möglicherweise nicht. Eigenschaften unterstützen zusätzliche Logik - dies könnte unter anderem verwendet werden, um ein verzögertes Laden zu implementieren.
Eigenschaften unterstützen eine Abstraktionsebene, indem sie kapseln, was auch immer es bedeutet, den Wert abzurufen / festzulegen.
Verwenden Sie in den meisten Fällen Eigenschaften, aber versuchen Sie, Nebenwirkungen zu vermeiden.
Im Hintergrund wird eine Eigenschaft in Methoden kompiliert. So wird eine Name
Eigenschaft in get_Name()
und kompiliert set_Name(string value)
. Sie können dies sehen, wenn Sie den kompilierten Code studieren. Daher entsteht bei der Verwendung ein (sehr) geringer Leistungsaufwand. Normalerweise verwenden Sie immer eine Eigenschaft, wenn Sie ein Feld nach außen offenlegen, und Sie verwenden sie häufig intern, wenn Sie eine Validierung des Werts durchführen müssen.
Wenn Sie möchten, dass Ihre private Variable (Feld) für Objekte Ihrer Klasse aus anderen Klassen zugänglich ist, müssen Sie Eigenschaften für diese Variablen erstellen.
Zum Beispiel, wenn ich Variablen mit den Namen "id" und "name" habe, die privat sind, aber es kann vorkommen, dass diese Variable für Lese- / Schreibvorgänge außerhalb der Klasse benötigt wird. In dieser Situation kann mir die Eigenschaft helfen, diese Variable in Abhängigkeit von der für die Eigenschaft definierten get / set zum Lesen / Schreiben zu bringen. Eine Eigenschaft kann sowohl schreibgeschützt als auch schreibgeschützt / schreibgeschützt sein.
Hier ist die Demo
class Employee
{
// Private Fields for Employee
private int id;
private string name;
//Property for id variable/field
public int EmployeeId
{
get
{
return id;
}
set
{
id = value;
}
}
//Property for name variable/field
public string EmployeeName
{
get
{
return name;
}
set
{
name = value;
}
}
}
class MyMain
{
public static void Main(string [] args)
{
Employee aEmployee = new Employee();
aEmployee.EmployeeId = 101;
aEmployee.EmployeeName = "Sundaran S";
}
}
Die zweite Frage hier, "wann sollte ein Feld anstelle einer Eigenschaft verwendet werden?", Wird in dieser anderen Antwort nur kurz angesprochen und irgendwie auch in dieser , aber nicht wirklich detailliert.
Im Allgemeinen sind alle anderen Antworten genau richtig für gutes Design: Belichten Sie lieber Eigenschaften als Felder. Während Sie wahrscheinlich nicht regelmäßig sagen werden: "Wow, stellen Sie sich vor, wie viel schlimmer es wäre, wenn ich dies zu einem Feld anstelle eines Grundstücks gemacht hätte", ist es so viel seltener, an eine Situation zu denken, in der Sie "Wow," sagen würden. Gott sei Dank habe ich hier ein Feld anstelle eines Grundstücks verwendet. "
Aber es gibt einen Vorteil, den Felder gegenüber Eigenschaften haben, und das ist ihre Fähigkeit, als "ref" / "out" -Parameter verwendet zu werden. Angenommen, Sie haben eine Methode mit der folgenden Signatur:
public void TransformPoint(ref double x, ref double y);
Angenommen, Sie möchten diese Methode verwenden, um ein wie folgt erstelltes Array zu transformieren:
System.Windows.Point[] points = new Point[1000000];
Initialize(points);
Hier ist meiner Meinung nach der schnellste Weg, da X und Y Eigenschaften sind:
for (int i = 0; i < points.Length; i++)
{
double x = points[i].X;
double y = points[i].Y;
TransformPoint(ref x, ref y);
points[i].X = x;
points[i].Y = y;
}
Und das wird ziemlich gut! Wenn Sie keine Messungen haben, die das Gegenteil beweisen, gibt es keinen Grund, einen Gestank zu werfen. Aber ich glaube, es ist technisch nicht garantiert, dass es so schnell geht:
internal struct MyPoint
{
internal double X;
internal double Y;
}
// ...
MyPoint[] points = new MyPoint[1000000];
Initialize(points);
// ...
for (int i = 0; i < points.Length; i++)
{
TransformPoint(ref points[i].X, ref points[i].Y);
}
Wenn Sie einige Messungen selbst durchführen, nimmt die Version mit Feldern etwa 61% der Zeit in Anspruch, da die Version mit Eigenschaften (.NET 4.6, Windows 7, x64, Release-Modus, kein Debugger angeschlossen). Je teurer die TransformPoint
Methode wird, desto weniger ausgeprägt wird der Unterschied. Um dies selbst zu wiederholen, führen Sie die erste Zeile auskommentiert und die nicht auskommentiert aus.
Selbst wenn es keine Leistungsvorteile für die oben genannten gibt, gibt es andere Stellen, an denen die Verwendung von ref- und out-Parametern von Vorteil sein kann, z. B. beim Aufrufen der Methodenfamilie Interlocked oder Volatile . Hinweis: Falls dies für Sie neu ist, ist Volatile im Grunde eine Möglichkeit, das gleiche Verhalten wie das volatile
Schlüsselwort zu erreichen. Als solches volatile
löst es nicht auf magische Weise alle Probleme mit der Thread-Sicherheit, wie der Name vermuten lässt.
Ich möchte definitiv nicht so aussehen, als würde ich befürworten, dass Sie sagen: "Oh, ich sollte anfangen, Felder anstelle von Eigenschaften freizulegen." Der Punkt ist, dass, wenn Sie diese Elemente regelmäßig in Aufrufen verwenden müssen, die "ref" - oder "out" -Parameter verwenden, insbesondere für einen einfachen Werttyp, für den wahrscheinlich nie eines der Mehrwertelemente von Eigenschaften erforderlich ist. es kann ein Argument vorgebracht werden.
Obwohl Felder und Eigenschaften einander ähnlich zu sein scheinen, sind sie zwei völlig unterschiedliche Sprachelemente.
Felder sind der einzige Mechanismus zum Speichern von Daten auf Klassenebene. Felder sind konzeptionell Variablen im Klassenbereich. Wenn Sie einige Daten in Instanzen Ihrer Klassen (Objekte) speichern möchten, müssen Sie Felder verwenden. Es gibt keine andere Wahl. Eigenschaften können keine Daten speichern, obwohl sie möglicherweise dazu in der Lage sind. Siehe unten.
Eigenschaften hingegen speichern niemals Daten. Sie sind nur die Methodenpaare (get und set), die auf ähnliche Weise wie Felder syntaktisch aufgerufen werden können, und in den meisten Fällen greifen sie auf (zum Lesen oder Schreiben) Felder zu, was zu Verwirrung führt. Da Eigenschaftsmethoden jedoch (mit einigen Einschränkungen wie dem festen Prototyp) reguläre C # -Methoden sind, können sie alle regulären Methoden ausführen. Dies bedeutet, dass sie 1000 Codezeilen haben können, Ausnahmen auslösen, andere Methoden aufrufen, sogar virtuell, abstrakt oder überschrieben sein können. Das Besondere an Eigenschaften ist die Tatsache, dass der C # -Compiler einige zusätzliche Metadaten in Assemblys speichert, mit denen nach bestimmten Eigenschaften gesucht werden kann - eine weit verbreitete Funktion.
Das Abrufen und Festlegen von Eigenschaftsmethoden umfasst die folgenden Prototypen.
PROPERTY_TYPE get();
void set(PROPERTY_TYPE value);
Dies bedeutet, dass Eigenschaften durch Definieren eines Felds und zweier entsprechender Methoden "emuliert" werden können.
class PropertyEmulation
{
private string MSomeValue;
public string GetSomeValue()
{
return(MSomeValue);
}
public void SetSomeValue(string value)
{
MSomeValue=value;
}
}
Eine solche Eigenschaftsemulation ist typisch für Programmiersprachen, die keine Eigenschaften unterstützen - wie Standard-C ++. In C # sollten Sie immer Eigenschaften bevorzugen, um auf Ihre Felder zugreifen zu können.
Da nur die Felder Daten speichern können, bedeutet dies, dass mehr Feldklassen enthalten und mehr Speicherobjekte dieser Klasse verbraucht werden. Wenn Sie jedoch einer Klasse neue Eigenschaften hinzufügen, werden Objekte dieser Klasse nicht größer. Hier ist das Beispiel.
class OneHundredFields
{
public int Field1;
public int Field2;
...
public int Field100;
}
OneHundredFields Instance=new OneHundredFields() // Variable 'Instance' consumes 100*sizeof(int) bytes of memory.
class OneHundredProperties
{
public int Property1
{
get
{
return(1000);
}
set
{
// Empty.
}
}
public int Property2
{
get
{
return(1000);
}
set
{
// Empty.
}
}
...
public int Property100
{
get
{
return(1000);
}
set
{
// Empty.
}
}
}
OneHundredProperties Instance=new OneHundredProperties() // !!!!! Variable 'Instance' consumes 0 bytes of memory. (In fact a some bytes are consumed becasue every object contais some auxiliarity data, but size doesn't depend on number of properties).
Obwohl Eigenschaftsmethoden alles können, dienen sie in den meisten Fällen als Möglichkeit, auf die Felder von Objekten zuzugreifen. Wenn Sie ein Feld für andere Klassen zugänglich machen möchten, haben Sie zwei Möglichkeiten.
Hier ist eine Klasse, die öffentliche Felder verwendet.
class Name
{
public string FullName;
public int YearOfBirth;
public int Age;
}
Name name=new Name();
name.FullName="Tim Anderson";
name.YearOfBirth=1979;
name.Age=40;
Obwohl der Code aus gestalterischer Sicht vollkommen gültig ist, weist er mehrere Nachteile auf. Da Felder sowohl gelesen als auch geschrieben werden können, können Sie den Benutzer nicht daran hindern, in Felder zu schreiben. Sie können ein readonly
Schlüsselwort anwenden , aber auf diese Weise müssen Sie schreibgeschützte Felder nur im Konstruktor initialisieren. Darüber hinaus hindert Sie nichts daran, ungültige Werte in Ihren Feldern zu speichern.
name.FullName=null;
name.YearOfBirth=2200;
name.Age=-140;
Der Code ist gültig, alle Zuweisungen werden ausgeführt, obwohl sie unlogisch sind. Age
hat einen negativen Wert, YearOfBirth
ist weit in der Zukunft und entspricht nicht dem Alter und FullName
ist null. Mit Feldern können Sie Benutzer nicht daran hindern class Name
, solche Fehler zu machen.
Hier ist ein Code mit Eigenschaften, der diese Probleme behebt.
class Name
{
private string MFullName="";
private int MYearOfBirth;
public string FullName
{
get
{
return(MFullName);
}
set
{
if (value==null)
{
throw(new InvalidOperationException("Error !"));
}
MFullName=value;
}
}
public int YearOfBirth
{
get
{
return(MYearOfBirth);
}
set
{
if (MYearOfBirth<1900 || MYearOfBirth>DateTime.Now.Year)
{
throw(new InvalidOperationException("Error !"));
}
MYearOfBirth=value;
}
}
public int Age
{
get
{
return(DateTime.Now.Year-MYearOfBirth);
}
}
public string FullNameInUppercase
{
get
{
return(MFullName.ToUpper());
}
}
}
Die aktualisierte Version der Klasse bietet die folgenden Vorteile.
FullName
und YearOfBirth
werden auf ungültige Werte überprüft.Age
ist nicht schreibbar. Es ist ab dem YearOfBirth
laufenden Jahr aufgerufen .FullNameInUppercase
wird FullName
in UPPER CASE konvertiert . Dies ist ein wenig erfundenes Beispiel für die Verwendung von Eigenschaften, bei dem Eigenschaften häufig verwendet werden, um Feldwerte in dem Format darzustellen, das für den Benutzer besser geeignet ist - beispielsweise unter Verwendung des aktuellen Gebietsschemas für eine bestimmte Formatnummer DateTime
.Darüber hinaus können Eigenschaften als virtuell oder überschrieben definiert werden - einfach weil es sich um reguläre .NET-Methoden handelt. Für solche Eigenschaftsmethoden gelten dieselben Regeln wie für reguläre Methoden.
C # unterstützt auch Indexer, bei denen es sich um Eigenschaften handelt, die in Eigenschaftsmethoden einen Indexparameter haben. Hier ist das Beispiel.
class MyList
{
private string[] MBuffer;
public MyList()
{
MBuffer=new string[100];
}
public string this[int Index]
{
get
{
return(MBuffer[Index]);
}
set
{
MBuffer[Index]=value;
}
}
}
MyList List=new MyList();
List[10]="ABC";
Console.WriteLine(List[10]);
Seit C # 3.0 können Sie automatische Eigenschaften definieren. Hier ist das Beispiel.
class AutoProps
{
public int Value1
{
get;
set;
}
public int Value2
{
get;
set;
}
}
Obwohl es class AutoProps
nur Eigenschaften enthält (oder so aussieht), kann es 2 Werte speichern und die Größe von Objekten dieser Klasse entspricht sizeof(Value1)+sizeof(Value2)
= 4 + 4 = 8 Bytes.
Der Grund dafür ist einfach. Wenn Sie eine automatische Eigenschaft definieren, generiert der C # -Compiler automatischen Code, der ein verstecktes Feld und eine Eigenschaft mit Eigenschaftsmethoden enthält, die auf dieses versteckte Feld zugreifen. Hier wird der Code-Compiler erstellt.
Hier ist ein Code, der von ILSpy aus einer kompilierten Assembly generiert wird . Klasse enthält generierte versteckte Felder und Eigenschaften.
internal class AutoProps
{
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int <Value1>k__BackingField;
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int <Value2>k__BackingField;
public int Value1
{
[CompilerGenerated]
get
{
return <Value1>k__BackingField;
}
[CompilerGenerated]
set
{
<Value1>k__BackingField = value;
}
}
public int Value2
{
[CompilerGenerated]
get
{
return <Value2>k__BackingField;
}
[CompilerGenerated]
set
{
<Value2>k__BackingField = value;
}
}
}
Wie Sie sehen, verwendet der Compiler die Felder weiterhin zum Speichern der Werte, da Felder die einzige Möglichkeit sind, Werte in Objekten zu speichern.
Wie Sie sehen können, sind Eigenschaften und Felder zwar eine ähnliche Verwendungssyntax, aber sehr unterschiedliche Konzepte. Selbst wenn Sie automatische Eigenschaften oder Ereignisse verwenden - versteckte Felder werden vom Compiler generiert, in dem die realen Daten gespeichert werden.
Wenn Sie einen Feldwert für die Außenwelt zugänglich machen müssen (Benutzer Ihrer Klasse), verwenden Sie keine öffentlichen oder geschützten Felder. Felder sollten immer als privat markiert werden. Mit den Eigenschaften können Sie Wertprüfungen, Formatierungen, Konvertierungen usw. durchführen und Ihren Code im Allgemeinen sicherer, lesbarer und erweiterbarer für zukünftige Änderungen machen.
Wenn Sie Thread-Grundelemente verwenden möchten, müssen Sie Felder verwenden. Eigenschaften können Ihren Thread-Code beschädigen. Abgesehen davon ist das, was Cory gesagt hat, richtig.
(Dies sollte eigentlich ein Kommentar sein, aber ich kann keinen Kommentar posten. Bitte entschuldigen Sie, wenn er nicht als Beitrag geeignet ist.)
Ich habe einmal an einem Ort gearbeitet, an dem empfohlen wurde, öffentliche Felder anstelle von Eigenschaften zu verwenden, wenn die entsprechende Eigenschaft def nur auf ein Feld zugegriffen hätte, wie in:
get { return _afield; }
set { _afield = value; }
Ihre Argumentation war, dass das öffentliche Feld bei Bedarf später in eine Immobilie umgewandelt werden könnte. Es kam mir damals etwas seltsam vor. Nach diesen Beiträgen zu urteilen, scheinen auch nicht viele hier zuzustimmen. Was könnten Sie gesagt haben, um zu versuchen, Dinge zu ändern?
Bearbeiten: Ich sollte hinzufügen, dass die gesamte Codebasis an dieser Stelle zur gleichen Zeit kompiliert wurde, sodass sie möglicherweise gedacht haben, dass das Ändern der öffentlichen Schnittstelle von Klassen (durch Ändern eines öffentlichen Felds in eine Eigenschaft) kein Problem darstellt.
Technisch gesehen glaube ich nicht, dass es einen Unterschied gibt, da Eigenschaften nur Wrapper um Felder sind, die vom Benutzer erstellt oder automatisch vom Compiler erstellt wurden. Der Zweck von Eigenschaften besteht darin, die Kapselung zu erzwingen und eine leichtgewichtige methodenähnliche Funktion anzubieten. Es ist nur eine schlechte Praxis, Felder als öffentlich zu deklarieren, aber es gibt keine Probleme.
Felder sind normale Mitgliedsvariablen oder Mitgliedsinstanzen einer Klasse. Eigenschaften sind eine Abstraktion, um ihre Werte abzurufen und festzulegen . Eigenschaften werden auch als Accessoren bezeichnet, da sie eine Möglichkeit bieten, ein Feld zu ändern und abzurufen, wenn Sie ein Feld in der Klasse als privat verfügbar machen. Im Allgemeinen sollten Sie Ihre Mitgliedsvariablen als privat deklarieren und dann Eigenschaften für sie deklarieren oder definieren.
class SomeClass
{
int numbera; //Field
//Property
public static int numbera { get; set;}
}
Eigenschaften kapseln Felder, sodass Sie zusätzliche Verarbeitung für den Wert vornehmen können, der festgelegt oder abgerufen werden soll. Die Verwendung von Eigenschaften ist in der Regel übertrieben, wenn Sie keine Vor- oder Nachbearbeitung für den Feldwert durchführen.
IMO, Eigenschaften sind nur die "SetXXX ()" "GetXXX ()" - Funktionen / Methoden / Schnittstellenpaare, die wir zuvor verwendet haben, aber sie sind prägnanter und eleganter.
Traditionell werden private Felder über Getter- und Setter-Methoden festgelegt. Um weniger Code zu erhalten, können Sie stattdessen Eigenschaften verwenden, um Felder festzulegen.
wenn Sie eine Klasse haben, die "Auto" ist. Die Eigenschaften sind Farbe, Form ..
Wobei als Felder Variablen sind, die im Bereich einer Klasse definiert sind.
Aus Wikipedia - Objektorientierte Programmierung :
Objektorientierte Programmierung (OOP) ist ein Programmierparadigma, das auf dem Konzept von "Objekten" basiert. Hierbei handelt es sich um Datenstrukturen, die Daten in Form von Feldern enthalten , die häufig als Attribute bezeichnet werden. und Code in Form von Prozeduren, die oft als Methoden bezeichnet werden . (Betonung hinzugefügt)
Eigenschaften sind tatsächlich Teil des Verhaltens eines Objekts, sollen den Verbrauchern des Objekts jedoch die Illusion / Abstraktion geben, mit den Daten des Objekts zu arbeiten.
Mein Entwurf eines Feldes ist, dass ein Feld nur von seinem übergeordneten Feld geändert werden muss, daher die Klasse. Das Ergebnis ist, dass die Variable privat wird. Um dann das Recht zu geben, die Klassen / Methoden außerhalb zu lesen, gehe ich nur mit Get durch das Eigenschaftssystem. Das Feld wird dann von der Eigenschaft abgerufen und ist schreibgeschützt! Wenn Sie es ändern möchten, müssen Sie Methoden (zum Beispiel den Konstruktor) durchlaufen, und ich finde, dass wir dank dieser Art der Sicherheit eine bessere Kontrolle über unseren Code haben, weil wir "flanschen". Man könnte sehr gut immer alles öffentlich machen, so dass jeder mögliche Fall, der Begriff der Variablen / Methoden / Klassen usw. meiner Meinung nach nur eine Hilfe für die Entwicklung, Pflege des Codes ist. Wenn eine Person beispielsweise einen Code mit öffentlichen Feldern wieder aufnimmt, kann sie alles und damit "unlogische" Dinge tun. in Bezug auf das Ziel die Logik, warum der Code geschrieben wurde. Es ist mein Standpunkt.
Wenn ich ein klassisches Modell für private Felder / öffentliche schreibgeschützte Eigenschaften verwende, sollte ich für 10 private Felder 10 öffentliche Eigenschaften schreiben! Der Code kann sehr schnell größer sein. Ich entdecke den privaten Setter und benutze jetzt nur öffentliche Eigenschaften mit einem privaten Setter. Der Setter erstellt im Hintergrund ein privates Feld.
Deshalb war mein alter klassischer Programmierstil:
public class MyClass
{
private int _id;
public int ID { get { return _id; } }
public MyClass(int id)
{
_id = id;
}
}
Mein neuer Programmierstil:
public class MyClass
{
public int ID { get; private set; }
public MyClass(int id)
{
ID = id;
}
}
Denken Sie darüber nach: Sie haben einen Raum und eine Tür, um diesen Raum zu betreten. Wenn Sie überprüfen möchten, wie wer hereinkommt, und Ihr Zimmer sichern möchten, sollten Sie Eigenschaften verwenden, da diese sonst keine Tür darstellen und jeder ohne Vorschrift problemlos hereinkommt
class Room {
public string sectionOne;
public string sectionTwo;
}
Room r = new Room();
r.sectionOne = "enter";
Die Leute kommen ziemlich leicht zu sectionOne, es gab keine Überprüfung
class Room
{
private string sectionOne;
private string sectionTwo;
public string SectionOne
{
get
{
return sectionOne;
}
set
{
sectionOne = Check(value);
}
}
}
Room r = new Room();
r.SectionOne = "enter";
Jetzt haben Sie die Person überprüft und wissen, ob sie etwas Böses bei sich hat
Felder sind die Variablen in Klassen. Felder sind die Daten, die Sie mithilfe von Zugriffsmodifikatoren kapseln können.
Eigenschaften sind Feldern insofern ähnlich, als sie Zustände und die einem Objekt zugeordneten Daten definieren.
Im Gegensatz zu einem Feld verfügt eine Eigenschaft über eine spezielle Syntax, die steuert, wie eine Person die Daten liest und schreibt. Diese werden als get- und set-Operatoren bezeichnet. Die eingestellte Logik kann häufig zur Validierung verwendet werden.
Eigenschaften sind spezielle Arten von Klassenmitgliedern. In Eigenschaften verwenden wir eine vordefinierte Set- oder Get-Methode. Sie verwenden Accessoren, mit denen wir die Werte der privaten Felder lesen, schreiben oder ändern können.
Nehmen wir zum Beispiel eine Klasse Employee
mit privaten Feldern für Name, Alter und Employee_Id. Wir können nicht von außerhalb der Klasse auf diese Felder zugreifen, aber wir können über Eigenschaften auf diese privaten Felder zugreifen.
Warum verwenden wir Eigenschaften?
Es ist riskant, das Klassenfeld öffentlich zu machen und es verfügbar zu machen, da Sie nicht die Kontrolle darüber haben, was zugewiesen und zurückgegeben wird.
Um dies anhand eines Beispiels klar zu verstehen, nehmen wir eine Schülerklasse mit Ausweis, Passmarke und Name. Nun in diesem Beispiel ein Problem mit dem öffentlichen Feld
Um dieses Problem zu beheben, verwenden wir die Methode Get and set.
// A simple example
public class student
{
public int ID;
public int passmark;
public string name;
}
public class Program
{
public static void Main(string[] args)
{
student s1 = new student();
s1.ID = -101; // here ID can't be -ve
s1.Name = null ; // here Name can't be null
}
}
Nun nehmen wir ein Beispiel für die Methode get and set
public class student
{
private int _ID;
private int _passmark;
private string_name ;
// for id property
public void SetID(int ID)
{
if(ID<=0)
{
throw new exception("student ID should be greater then 0");
}
this._ID = ID;
}
public int getID()
{
return_ID;
}
}
public class programme
{
public static void main()
{
student s1 = new student ();
s1.SetID(101);
}
// Like this we also can use for Name property
public void SetName(string Name)
{
if(string.IsNullOrEmpty(Name))
{
throw new exeception("name can not be null");
}
this._Name = Name;
}
public string GetName()
{
if( string.IsNullOrEmpty(This.Name))
{
return "No Name";
}
else
{
return this._name;
}
}
// Like this we also can use for Passmark property
public int Getpassmark()
{
return this._passmark;
}
}
Zusätzliche Informationen: Standardmäßig sind get- und set-Accessoren genauso zugänglich wie die Eigenschaft selbst. Sie können die Zugänglichkeit von Accessoren individuell steuern / einschränken (zum Abrufen und Festlegen), indem Sie restriktivere Zugriffsmodifikatoren auf sie anwenden.
Beispiel:
public string Name
{
get
{
return name;
}
protected set
{
name = value;
}
}
Hier wird auf get immer noch öffentlich zugegriffen (da die Eigenschaft öffentlich ist), aber set ist geschützt (ein eingeschränkter Zugriffsspezifizierer).
Eigenschaften werden verwendet, um Felder verfügbar zu machen. Sie verwenden Accessoren (set, get), mit denen die Werte der privaten Felder gelesen, geschrieben oder bearbeitet werden können.
Eigenschaften benennen die Speicherorte nicht. Stattdessen verfügen sie über Accessoren, die ihre Werte lesen, schreiben oder berechnen.
Mithilfe von Eigenschaften können wir die Validierung für den Datentyp festlegen, der für ein Feld festgelegt wird.
Zum Beispiel haben wir ein privates ganzzahliges Feldalter, bei dem wir positive Werte zulassen sollten, da das Alter nicht negativ sein kann.
Wir können dies auf zwei Arten tun, indem wir Getter und Setter verwenden und Eigenschaft verwenden.
Using Getter and Setter
// field
private int _age;
// setter
public void set(int age){
if (age <=0)
throw new Exception();
this._age = age;
}
// getter
public int get (){
return this._age;
}
Now using property we can do the same thing. In the value is a key word
private int _age;
public int Age{
get{
return this._age;
}
set{
if (value <= 0)
throw new Exception()
}
}
Automatisch implementierte Eigenschaft Wenn wir in get- und set-Accessoren keine Logik verwenden, können wir die automatisch implementierte Eigenschaft verwenden.
Wenn Sie automatisch implementierte Eigenschaftskompilierungen verwenden, wird ein privates, anonymes Feld erstellt , auf das nur über get- und set-Accessoren zugegriffen werden kann.
public int Age{get;set;}
Abstrakte Eigenschaften Eine abstrakte Klasse kann eine abstrakte Eigenschaft haben, die in der abgeleiteten Klasse implementiert werden sollte
public abstract class Person
{
public abstract string Name
{
get;
set;
}
public abstract int Age
{
get;
set;
}
}
// overriden something like this
// Declare a Name property of type string:
public override string Name
{
get
{
return name;
}
set
{
name = value;
}
}
Wir können eine Eigenschaft privat festlegen. Hier können wir die Eigenschaft auto privat festlegen (in der Klasse mit).
public int MyProperty
{
get; private set;
}
Sie können dasselbe mit diesem Code erreichen. In dieser Eigenschaft ist die Funktion nicht verfügbar, da der Wert direkt auf das Feld festgelegt werden muss.
private int myProperty;
public int MyProperty
{
get { return myProperty; }
}
In den allermeisten Fällen handelt es sich um einen Eigenschaftsnamen, auf den Sie zugreifen, im Gegensatz zu einem Variablennamen ( Feld ). Der Grund dafür ist, dass dies in .NET und insbesondere in C # als bewährte Methode angesehen wird, um alle Daten innerhalb einer Klasse zu schützen , ob es sich um eine Instanzvariable oder eine statische Variable (Klassenvariable) handelt, da sie einer Klasse zugeordnet ist.
Schützen Sie alle diese Variablen mit entsprechenden Eigenschaften, mit denen Sie Accessoren definieren, festlegen und abrufen sowie Validierungen durchführen können, wenn Sie diese Daten bearbeiten.
In anderen Fällen wie der Math-Klasse (System-Namespace) sind jedoch einige statische Eigenschaften in die Klasse integriert. Eine davon ist die mathematische Konstante PI
z.B. Math.PI
und da PI ein genau definiertes Datenelement ist, benötigen wir nicht mehrere Kopien von PI, es wird immer der gleiche Wert sein. Daher werden manchmal statische Variablen verwendet, um Daten zwischen Objekten einer Klasse gemeinsam zu nutzen. Diese Variablen werden jedoch häufig auch für konstante Informationen verwendet, bei denen Sie nur eine Kopie eines Datenelements benötigen.