Zoeken…


Opmerkingen

Eigenschappen combineren de klassegegevensopslag van velden met de toegankelijkheid van methoden. Soms kan het moeilijk zijn om te beslissen of een eigenschap, een eigenschap die naar een veld verwijst, of een methode die naar een veld verwijst, moet worden gebruikt. Als vuistregel:

  • Eigenschappen moeten worden gebruikt zonder een intern veld als ze alleen waarden krijgen en / of instellen; zonder andere logica. In dergelijke gevallen zou het toevoegen van een intern veld code toevoegen zonder voordeel.

  • Eigenschappen moeten worden gebruikt met interne velden wanneer u de gegevens moet manipuleren of valideren. Een voorbeeld is het verwijderen van voorloop- en volgspaties uit tekenreeksen of ervoor zorgen dat een datum niet in het verleden ligt.

Met betrekking tot Methoden vs Properties, waar je zowel kunt ophalen ( get ) en updaten ( set ) een waarde, een eigenschap is de betere keuze. Ook biedt .Net veel functionaliteit die gebruik maakt van de structuur van een klasse; bijv. door een raster aan een formulier toe te voegen, toont .Net standaard alle eigenschappen van de klasse op dat formulier; dus om optimaal gebruik te maken van dergelijke conventies, zijn van plan eigenschappen te gebruiken wanneer dit gedrag doorgaans wenselijk zou zijn, en methoden waarbij u wilt dat de typen niet automatisch worden toegevoegd.

Verschillende eigenschappen in context

public class Person 
{
    //Id property can be read by other classes, but only set by the Person class
    public int Id {get; private set;}
    //Name property can be retrieved or assigned 
    public string Name {get; set;}
    
    private DateTime dob;
    //Date of Birth property is stored in a private variable, but retrieved or assigned through the public property.
    public DateTime DOB
    {
        get { return this.dob; }
        set { this.dob = value; }
    }
    //Age property can only be retrieved; it's value is derived from the date of birth 
    public int Age 
    {
        get 
        {
            int offset = HasHadBirthdayThisYear() ? 0 : -1;
            return DateTime.UtcNow.Year - this.dob.Year + offset;
        }
    }

    //this is not a property but a method; though it could be rewritten as a property if desired.
    private bool HasHadBirthdayThisYear() 
    {
        bool hasHadBirthdayThisYear = true;
        DateTime today = DateTime.UtcNow;
        if (today.Month > this.dob.Month)
        {
            hasHadBirthdayThisYear = true;
        }
        else 
        {
            if (today.Month == this.dob.Month)
            {
                hasHadBirthdayThisYear = today.Day > this.dob.Day;
            }
            else
            {
                hasHadBirthdayThisYear = false;
            }
        }
        return hasHadBirthdayThisYear;
    }
}

Openbaar ophalen

Getters worden gebruikt om waarden uit klassen bloot te leggen.

string name;
public string Name
{
    get { return this.name; }
}

Publieke Set

Setters worden gebruikt om waarden toe te wijzen aan eigenschappen.

string name;
public string Name 
{
    set { this.name = value; }
}

Toegang tot eigenschappen

class Program 
{
    public static void Main(string[] args)
    {
        Person aPerson = new Person("Ann Xena Sample", new DateTime(1984, 10, 22));
        //example of accessing properties (Id, Name & DOB)
        Console.WriteLine("Id is:  \t{0}\nName is:\t'{1}'.\nDOB is: \t{2:yyyy-MM-dd}.\nAge is: \t{3}", aPerson.Id, aPerson.Name, aPerson.DOB, aPerson.GetAgeInYears());
        //example of setting properties

        aPerson.Name = "   Hans Trimmer  ";
        aPerson.DOB = new DateTime(1961, 11, 11);
        //aPerson.Id = 5; //this won't compile as Id's SET method is private; so only accessible within the Person class.
        //aPerson.DOB = DateTime.UtcNow.AddYears(1); //this would throw a runtime error as there's validation to ensure the DOB is in past. 

        //see how our changes above take effect; note that the Name has been trimmed
        Console.WriteLine("Id is:  \t{0}\nName is:\t'{1}'.\nDOB is: \t{2:yyyy-MM-dd}.\nAge is: \t{3}", aPerson.Id, aPerson.Name, aPerson.DOB, aPerson.GetAgeInYears());

        Console.WriteLine("Press any key to continue");
        Console.Read();
    }
}

public class Person
{
    private static int nextId = 0;
    private string name;
    private DateTime dob; //dates are held in UTC; i.e. we disregard timezones
    public Person(string name, DateTime dob)
    {
        this.Id = ++Person.nextId;
        this.Name = name;
        this.DOB = dob;
    }
    public int Id
    {
        get;
        private set;
    }
    public string Name
    {
        get { return this.name; }
        set
        {
            if (string.IsNullOrWhiteSpace(value)) throw new InvalidNameException(value);
            this.name = value.Trim();
        }
    }
    public DateTime DOB
    {
        get { return this.dob; }
        set 
        {
            if (value < DateTime.UtcNow.AddYears(-200) || value > DateTime.UtcNow) throw new InvalidDobException(value);
            this.dob = value; 
        }
    }
    public int GetAgeInYears()
    {
        DateTime today = DateTime.UtcNow;
        int offset = HasHadBirthdayThisYear() ? 0 : -1;
        return today.Year - this.dob.Year + offset;
    }
    private bool HasHadBirthdayThisYear()
    {
        bool hasHadBirthdayThisYear = true;
        DateTime today = DateTime.UtcNow;
        if (today.Month > this.dob.Month)
        {
            hasHadBirthdayThisYear = true;
        }
        else
        {
            if (today.Month == this.dob.Month)
            {
                hasHadBirthdayThisYear = today.Day > this.dob.Day;
            }
            else
            {
                hasHadBirthdayThisYear = false;
            }
        }
        return hasHadBirthdayThisYear;
    }
}

public class InvalidNameException : ApplicationException
{
    const string InvalidNameExceptionMessage = "'{0}' is an invalid name.";
    public InvalidNameException(string value): base(string.Format(InvalidNameExceptionMessage,value)){}
}
public class InvalidDobException : ApplicationException
{ 
    const string InvalidDobExceptionMessage = "'{0:yyyy-MM-dd}' is an invalid DOB.  The date must not be in the future, or over 200 years in the past.";
    public InvalidDobException(DateTime value): base(string.Format(InvalidDobExceptionMessage,value)){}
}

Standaardwaarden voor eigenschappen

Het instellen van een standaardwaarde kan worden gedaan met behulp van initializers (C # 6)

public class Name 
{
    public string First { get; set; } = "James";
    public string Last { get; set; } = "Smith";
}

Als het alleen wordt gelezen, kunt u waarden als volgt retourneren:

  public class Name 
  {
      public string First => "James";
      public string Last => "Smith";
  }

Automatisch geïmplementeerde eigenschappen

Auto-geïmplementeerde eigenschappen zijn geïntroduceerd in C # 3.
Een automatisch geïmplementeerde eigenschap wordt gedeclareerd met een lege getter en setter (accessors):

public bool IsValid { get; set; }

Wanneer een automatisch geïmplementeerde eigenschap in uw code wordt geschreven, maakt de compiler een anoniem privéveld dat alleen toegankelijk is via de accessors van de eigenschap.

De bovenstaande automatisch geïmplementeerde eigenschapsverklaring is gelijk aan het schrijven van deze lange code:

private bool _isValid;
public bool IsValid
{
    get { return _isValid; }
    set { _isValid = value; }
}

Automatisch geïmplementeerde eigenschappen kunnen geen logica in hun accessors hebben, bijvoorbeeld:

public bool IsValid { get; set { PropertyChanged("IsValid"); } } // Invalid code

Een automatisch geïmplementeerde eigenschap kan echter verschillende toegangsmodificaties hebben voor zijn accessors:

public bool IsValid { get; private set; }    

C # 6 zorgt ervoor dat automatisch geïmplementeerde eigenschappen helemaal geen setter hebben (waardoor het onveranderlijk is, omdat de waarde ervan alleen binnen de constructor kan worden ingesteld of hard gecodeerd):

public bool IsValid { get; }    
public bool IsValid { get; } = true;

Voor meer informatie over het initialiseren van auto-geïmplementeerd eigenschappen, lees de Auto-eigenschap initialiseerders documentatie.

Alleen-lezen eigenschappen

Verklaring

Een veel voorkomend misverstand, met name voor beginners, is alleen-lezen eigenschap die is gemarkeerd met readonly trefwoord. Dat is niet correct en in feite is er een compilatietijdfout :

public readonly string SomeProp { get; set; }

Een eigenschap is alleen-lezen wanneer deze alleen een getter heeft.

public string SomeProp { get; }

Alleen-lezen eigenschappen gebruiken om onveranderlijke klassen te maken

public Address
{
    public string ZipCode { get; }
    public string City { get; }
    public string StreetAddress { get; }

    public Address(
        string zipCode,
        string city,
        string streetAddress)
    {
        if (zipCode == null)
            throw new ArgumentNullException(nameof(zipCode));
        if (city == null)
            throw new ArgumentNullException(nameof(city));
        if (streetAddress == null)
            throw new ArgumentNullException(nameof(streetAddress));

        ZipCode = zipCode;
        City = city;
        StreetAddress = streetAddress;
    }
}


Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow