[c#] Was ist der Unterschied zwischen einem Feld und einer Eigenschaft?



Answers

Objektorientierte Programmierungsprinzipien sagen, dass das interne Arbeiten einer Klasse von der Außenwelt verborgen sein sollte. Wenn Sie ein Feld verfügbar machen, stellen Sie im Wesentlichen die interne Implementierung der Klasse offen. Daher umschließen wir Felder mit Eigenschaften (oder Methoden im Fall von Java), um uns die Möglichkeit zu geben, die Implementierung zu ändern, ohne Code zu brechen, abhängig von uns. Da wir die Logik in die Eigenschaft einfügen können, können wir auch eine Validierungslogik usw. ausführen, wenn wir sie brauchen. C # 3 hat die möglicherweise verwirrende Vorstellung von Autoproperties. Dies erlaubt uns, einfach die Eigenschaft zu definieren, und der C # 3-Compiler erzeugt 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
}
Question

In C #, was unterscheidet ein Feld von einer Eigenschaft und wann sollte ein Feld anstelle einer Eigenschaft verwendet werden?




Ich gebe Ihnen ein paar Beispiele für die Verwendung von Eigenschaften, die die Zahnräder drehen könnten:

  • Lazy Initialization ( Lazy-Initialisierung) : Wenn Sie eine Eigenschaft eines Objekts haben, deren Laden teuer ist, auf die bei normalen Code-Läufen jedoch nicht viel zugegriffen wird, können Sie das Laden über die Eigenschaft verzögern. Auf diese Weise sitzt es nur dort, aber wenn ein anderes Modul zum ersten Mal versucht, diese Eigenschaft aufzurufen, prüft es, ob das zugrundeliegende Feld null ist - wenn es ist, wird es weiter ausgeführt und lädt es, unbekannt für das aufrufende Modul. Dies kann die Objektinitialisierung erheblich beschleunigen.
  • Dirty Tracking: Was ich über meine eigene Frage hier auf erfahren habe. Wenn ich viele Objekte habe, deren Werte sich während eines Laufs geändert haben, kann ich mit der Eigenschaft verfolgen, ob sie in der Datenbank gespeichert werden müssen oder nicht. Wenn sich nicht eine einzelne Eigenschaft eines Objekts geändert hat, wird das IsDirty-Flag nicht ausgelöst, und daher wird die Speicherfunktion es überspringen, wenn entschieden wird, was zurück in die Datenbank gehen soll.



IMO, Eigenschaften sind nur die "SetXXX ()" "GetXXX ()" -Funktionen / Methoden / Schnittstellen-Paare, die wir vorher verwendet haben, aber sie sind prägnanter und eleganter.







wenn Sie eine Klasse haben, die "Auto" ist. Die Eigenschaften sind Farbe, Form ..

Wobei als Felder Variablen definiert sind, die innerhalb des Bereichs einer Klasse definiert sind.




Eigenschaften kapseln Felder ein, so dass Sie eine zusätzliche Verarbeitung für den Wert ausführen können, der festgelegt oder abgerufen werden soll. Es ist in der Regel übertrieben, Eigenschaften zu verwenden, wenn Sie für den Feldwert keine Vor- oder Nachbearbeitung durchführen.




Da viele von ihnen mit technischen Vor- und Nachteilen von Properties und Field , ist es Zeit, in Echtzeit-Beispiele zu kommen.

1. Eigenschaften können Sie die schreibgeschützte Zugriffsebene festlegen

Betrachten Sie den Fall von dataTable.Rows.Count und dataTable.Columns[i].Caption . Sie stammen aus der Klasse DataTable und beide sind für uns öffentlich. Der Unterschied in der Zugriffsebene zu ihnen ist, dass wir keinen Wert auf dataTable.Rows.Count setzen können, aber wir können lesen und schreiben in dataTable.Columns[i].Caption . Ist das durch Field möglich? Nein!!! Dies kann nur mit 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

Sie haben möglicherweise mit Button in Visual Studio gearbeitet. Seine Eigenschaften werden im PropertyGrid wie Text , Name usw. angezeigt. Wenn wir eine Schaltfläche ziehen und ablegen und auf die Eigenschaften klicken, findet sie automatisch die Klasse Button und filtert Properties und zeigt dies in PropertyGrid (wobei PropertyGrid nicht angezeigt wird) Field , obwohl 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, nicht jedoch SomeProperty . Warum??? Weil Eigenschaften Attributes annehmen können. Es wird nicht [Browsable(false)] wenn [Browsable(false)] falsch ist.

3. Kann Anweisungen innerhalb von Properties 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

Binding Source hilft uns, die Anzahl der Codezeilen zu verringern. Fields werden von BindingSource nicht akzeptiert. Wir sollten Properties dafür verwenden.

5. Debugging-Modus

Überlegen Sie, dass wir 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, zu tun, wo die Anzahl der Codezeilen mehr als 1000 ist. In solchen Situationen können wir Property und den Debug-Modus in Property .

   public string Name
   {
        // Can set debug mode inside get or set
        get
        {
           return _name;
        }
        set
        {
           _name = value;
        }
   }



Im Hintergrund wird eine Eigenschaft in Methoden kompiliert. Daher wird eine Name Eigenschaft in get_Name() und set_Name(string value) kompiliert. Sie können dies sehen, wenn Sie den kompilierten Code studieren. Es gibt also einen (sehr) geringen Leistungsaufwand bei der Verwendung. Normalerweise verwenden Sie immer eine Eigenschaft, wenn Sie ein Feld nach außen freigeben, und Sie werden es oft intern verwenden, wenn Sie den Wert validieren müssen.




The vast majority of cases it's going to be a property name that you access as opposed to a variable name ( field ) The reason for that is it's considered good practice in .NET and in C# in particular to protect every piece of data within a class, whether it's an instance variable or a static variable (class variable) because it's associated with a class.

Protect all of those variables with corresponding properties which allow you to define, set and get accessors and do things like validation when you're manipulating those pieces of data.

But in other cases like Math class (System namespace), there are a couple of static properties that are built into the class. one of which is the math constant PI

z.B. Math.PI

and because PI is a piece of data that is well-defined, we don't need to have multiple copies of PI, it always going to be the same value. So static variables are sometimes used to share data amongst object of a class, but the are also commonly used for constant information where you only need one copy of a piece of data.




Die zweite Frage, "wann sollte ein Feld anstelle einer Eigenschaft verwendet werden?", Wird in dieser anderen Antwort nur kurz gestreift , und zwar auch diese , aber nicht sehr detailliert.

Im Allgemeinen sind alle anderen Antworten genau auf gutes Design ausgerichtet: Sie bevorzugen es, die Eigenschaften gegenüber den Belichtungsfeldern zu exponieren. Während Sie sich wahrscheinlich nicht regelmäßig sagen werden: "Wow, stell dir vor, wie viel schlimmer es wäre, wenn ich dies zu einem Feld anstelle einer Eigenschaft gemacht hätte", ist es viel seltener, an eine Situation zu denken, in der du sagen würdest: "Wow, Gott sei Dank habe ich hier ein Feld statt eines Grundstücks benutzt. "

Aber es gibt einen Vorteil, dass Felder über Eigenschaften verfügen, und das ist ihre Fähigkeit, als "ref" / "out" Parameter verwendet zu werden. Angenommen, Sie haben eine Methode mit folgender Signatur:

public void TransformPoint(ref double x, ref double y);

Angenommen, Sie möchten diese Methode verwenden, um ein Array zu transformieren, das wie folgt erstellt wurde:

System.Windows.Point[] points = new Point[1000000];
Initialize(points);

Hier ist der schnellste Weg, denn X und Y sind Eigenschaften:

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

Bei einigen measurements dauert die Version mit Feldern etwa 61% der Zeit als Version mit Eigenschaften (.NET 4.6, Windows 7, x64, Freigabemodus, kein Debugger angeschlossen). Je teurer die TransformPoint Methode wird, desto weniger ausgeprägt ist der Unterschied. Um dies selbst zu wiederholen, laufen Sie mit der ersten Zeile auskommentiert und damit nicht auskommentiert.

Selbst wenn es keine Leistungsvorteile für das oben genannte gibt, gibt es andere Stellen, an denen die Verwendung von ref- und out-Parametern vorteilhaft sein kann, wie beim Aufruf der Methodenfamilie " Interlocked oder " Volatile . Hinweis: Falls dies für Sie neu ist, ist Volatile im Prinzip eine Möglichkeit, das gleiche Verhalten zu erhalten wie das volatile Schlüsselwort. Als solches, wie volatile , löst es nicht magisch alle Thread-Sicherheitsprobleme, wie sein Name andeutet, dass es könnte.

Ich will definitiv nicht so aussehen, als ob ich befürworte, dass du gehst "Oh, ich sollte anfangen, Felder anstatt Eigenschaften auszusetzen." Der Punkt ist, dass, wenn Sie diese Member regelmäßig in Aufrufen verwenden müssen, die "Ref" - oder "Out" -Parameter verwenden, besonders bei etwas, das ein einfacher Werttyp sein könnte, der wahrscheinlich keines der wertschöpfenden Elemente von Eigenschaften benötigt. ein Argument kann gemacht werden.




Wenn Sie Thread-Primitive verwenden, müssen Sie Felder verwenden. Eigenschaften können den Thread-Code unterbrechen. Abgesehen davon, was Cory gesagt hat, ist richtig.




Eigenschaften sind eine besondere Art von Klassenmember. In Eigenschaften verwenden wir eine vordefinierte Set- oder Get-Methode. Sie verwenden Accessoren, über die wir die Werte der privaten Felder lesen, schreiben oder ändern können.

Nehmen wir zum Beispiel eine Klasse namens Employee mit privaten Feldern für name, age und Employee_Id. Wir können nicht von außerhalb der Klasse auf diese Felder zugreifen, aber wir können auf diese privaten Felder über Eigenschaften zugreifen.

Warum verwenden wir Eigenschaften?

Es ist riskant, das Klassenfeld öffentlich zu machen und es offenzulegen, da Sie nicht kontrollieren können, was zugewiesen und zurückgegeben wird.

Um dies mit einem Beispiel klar zu verstehen, nehmen Sie eine Schülerklasse mit ID, Passwort, Name. Jetzt in diesem Beispiel ein Problem mit dem öffentlichen Feld

  • ID sollte nicht -ve sein.
  • Name kann nicht auf null festgelegt werden
  • Pass-Marke sollte nur gelesen werden.
  • Wenn der Name des Schülers fehlt, sollte kein Name zurückgegeben werden.

Um dieses Problem zu beheben, verwenden wir die Get-Methode.

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

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



Eigenschaften haben den Hauptvorteil, dass Sie die Art ändern können, in der auf Daten auf einem Objekt zugegriffen wird, ohne die öffentliche Schnittstelle zu unterbrechen. Wenn Sie beispielsweise eine zusätzliche Überprüfung hinzufügen oder ein gespeichertes Feld in ein berechnetes Feld ändern möchten, können Sie dies leicht tun, wenn Sie das Feld zunächst als Eigenschaft angezeigt haben. Wenn Sie ein Feld direkt angezeigt haben, müssten Sie die öffentliche Schnittstelle Ihrer Klasse ändern, um die neue Funktionalität hinzuzufügen. Durch diese Änderung werden vorhandene Clients getrennt und müssen neu kompiliert werden, bevor sie die neue Version Ihres Codes verwenden können.

Wenn Sie eine Klassenbibliothek schreiben, die für eine breite Verwendung konzipiert ist (wie das .NET Framework, das von Millionen von Benutzern verwendet wird), kann das ein Problem sein. Wenn Sie jedoch eine Klasse schreiben, die intern in einer kleinen Codebasis verwendet wird (sagen wir <= 50 K-Zeilen), ist das wirklich keine große Sache, weil niemand von Ihren Änderungen beeinträchtigt wird. In diesem Fall kommt es wirklich nur auf persönliche Vorlieben an.




Properties are used to expose field. They use accessors(set, get) through which the values of the private fields can be read, written or manipulated.

Properties do not name the storage locations. Instead, they have accessors that read, write, or compute their values.

Using properties we can set validation on the type of data that is set on a field.

For example we have private integer field age on that we should allow positive values since age cannot be negative.

We can do this in two ways using getter and setters and using property.

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

Auto Implemented property if we don't logic in get and set accessors we can use auto implemented property.

When u se auto-implemented property compiles creates a private, anonymous field that can only be accessed through get and set accessors.

public int Age{get;set;}

Abstract Properties An abstract class may have an abstract property, which should be implemented in the derived class

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

We can privately set a property In this we can privately set the auto property(set with in the class)

public int MyProperty
{
    get; private set;
}

You can achieve same with this code. In this property set feature is not available as we have to set value to field directly.

private int myProperty;
public int MyProperty
{
    get { return myProperty; }
}



Related