Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharpNotesForProfessionals.pdf
Скачиваний:
65
Добавлен:
20.05.2023
Размер:
6.12 Mб
Скачать

Chapter 86: Properties

Section 86.1: Auto-implemented properties

Auto-implemented properties were introduced in C# 3.

An auto-implemented property is declared with an empty getter and setter (accessors):

public bool IsValid { get; set; }

When an auto-implemented property is written in your code, the compiler creates a private anonymous field that can only be accessed through the property's accessors.

The above auto-implemented property statement is equivalent to writing this lengthy code:

private bool _isValid; public bool IsValid

{

get { return _isValid; } set { _isValid = value; }

}

Auto-implemented properties cannot have any logic in their accessors, for example:

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

An auto-implemented property can however have di erent access modifiers for its accessors:

public bool IsValid { get; private set; }

C# 6 allows auto-implemented properties to have no setter at all (making it immutable, since its value can be set only inside the constructor or hard coded):

public bool IsValid { get; }

public bool IsValid { get; } = true;

For more information on initializing auto-implemented properties, read the Auto-property initializers documentation.

Section 86.2: Default Values for Properties

Setting a default value can be done by using Initializers (C#6)

public class Name

{

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

}

If it is read only you can return values like this:

public class Name

{

public string First => "James"; public string Last => "Smith";

GoalKicker.com – C# Notes for Professionals

485

}

Section 86.3: Public Get

Getters are used to expose values from classes.

string name; public string Name

{

get { return this.name; }

}

Section 86.4: Public Set

Setters are used to assign values to properties.

string name; public string Name

{

set { this.name = value; }

}

Section 86.5: Accessing Properties

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;

GoalKicker.com – C# Notes for Professionals

486

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

GoalKicker.com – C# Notes for Professionals

487

{

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

}

Section 86.6: Read-only properties

Declaration

A common misunderstanding, especially beginners, have is read-only property is the one marked with readonly keyword. That's not correct and in fact following is a compile time error:

public readonly string SomeProp { get; set; }

A property is read-only when it only has a getter.

public string SomeProp { get; }

Using read-only properties to create immutable classes

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;

}

}

Section 86.7: Various Properties 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

{

GoalKicker.com – C# Notes for Professionals

488

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;

}

}

GoalKicker.com – C# Notes for Professionals

489