This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
Note
Access to this page requires authorization. You can trysigning in orchanging directories.
Access to this page requires authorization. You can trychanging directories.
Aproperty is a member that provides a flexible mechanism to read, write, or compute the value of a data field. Properties appear as public data members, but they're implemented as special methods calledaccessors. This feature enables callers to access data easily and still helps promote data safety and flexibility. The syntax for properties is a natural extension to fields. A field defines a storage location:
public class Person{ public string? FirstName; // Omitted for brevity.}A property definition contains declarations for aget andset accessor that retrieves and assigns the value of that property:
public class Person{ public string? FirstName { get; set; } // Omitted for brevity.}The preceding example shows anautomatically implemented property. The compiler generates a hidden backing field for the property. The compiler also implements the body of theget andset accessors. Any attributes are applied to the automatically implemented property. You can apply the attribute to the compiler-generated backing field by specifying thefield: tag on the attribute.
You can initialize a property to a value other than the default by setting a value after the closing brace for the property. You might prefer the initial value for theFirstName property to be the empty string rather thannull. You would specify that as shown in the following code:
public class Person{ public string FirstName { get; set; } = string.Empty; // Omitted for brevity.}In C# 14, you can add validation or other logic in the accessor for a property using thefield keyword. Thefield keyword accesses the compiler synthesized backing field for a property. It enables you to write a property accessor without explicitly declaring a separate backing field.
public class Person{ public string? FirstName { get; set => field = value.Trim(); } // Omitted for brevity.}The preceding example allows a caller to create aPerson using the default constructor, without setting theFirstName property. The property changed type to anullable string. You canrequire callers to set a property:
public class Person{ public Person() { } [SetsRequiredMembers] public Person(string firstName) => FirstName = firstName; public required string FirstName { get; init; } // Omitted for brevity.}The preceding code makes two changes to thePerson class. First, theFirstName property declaration includes therequired modifier. That means any code that creates a newPerson must set this property using anobject initializer. Second, the constructor that takes afirstName parameter has theSystem.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute attribute. This attribute informs the compiler that this constructor setsallrequired members. Callers using this constructor aren't required to setrequired properties with an object initializer.
Important
Don't confuserequired withnon-nullable. It's valid to set arequired property tonull ordefault. If the type is non-nullable, such asstring in these examples, the compiler issues a warning.
var aPerson = new Person("John");aPerson = new Person { FirstName = "John"};// Error CS9035: Required member `Person.FirstName` must be set://aPerson2 = new Person();Property accessors often consist of single-line statements. The accessors assign or return the result of an expression. You can implement these properties as expression-bodied members. Expression body definitions consist of the=> token followed by the expression to assign to or retrieve from the property.
Read-only properties can implement theget accessor as an expression-bodied member. The following example implements the read-onlyName property as an expression-bodied member:
public class Person{ public Person() { } [SetsRequiredMembers] public Person(string firstName, string lastName) { FirstName = firstName; LastName = lastName; } public required string FirstName { get; init; } public required string LastName { get; init; } public string Name => $"{FirstName} {LastName}"; // Omitted for brevity.}TheName property is a computed property. There's no backing field forName. The property computes it each time.
The preceding examples showed read / write properties. You can also create read-only properties, or give different accessibility to the set and get accessors. Suppose that yourPerson class should only enable changing the value of theFirstName property from other methods in the class. You could give the set accessorprivate accessibility instead ofinternal orpublic:
public class Person{ public string? FirstName { get; private set; } // Omitted for brevity.}TheFirstName property can be read from any code, but it can be assigned only from code in thePerson class.
You can add any restrictive access modifier to either the set or get accessors. An access modifier on an individual accessor must be more restrictive than the access of the property. The preceding code is legal because theFirstName property ispublic, but the set accessor isprivate. You couldn't declare aprivate property with apublic accessor. Property declarations can also be declaredprotected,internal,protected internal, or, evenprivate.
There are two special access modifiers forset accessors:
set accessor can haveinit as its access modifier. Thatset accessor can be called only from an object initializer or the type's constructors. It's more restrictive thanprivate on theset accessor.get accessor without aset accessor. In that case, the compiler allows theset accessor to be called only from the type's constructors. It's more restrictive than theinit accessor on theset accessor.Modify thePerson class so as follows:
public class Person{ public Person(string firstName) => FirstName = firstName; public string FirstName { get; } // Omitted for brevity.}The preceding example requires callers to use the constructor that includes theFirstName parameter. Callers can't useobject initializers to assign a value to the property. To support initializers, you can make theset accessor aninit accessor, as shown in the following code:
public class Person{ public Person() { } public Person(string firstName) => FirstName = firstName; public string? FirstName { get; init; } // Omitted for brevity.}These modifiers are often used with therequired modifier to force proper initialization.
You can mix the concept of a computed property with a private field and create acached evaluated property. For example, update theFullName property so that the string formatting happens on the first access:
public class Person{ public Person() { } [SetsRequiredMembers] public Person(string firstName, string lastName) { FirstName = firstName; LastName = lastName; } public required string FirstName { get; init; } public required string LastName { get; init; } private string? _fullName; public string FullName { get { if (_fullName is null) _fullName = $"{FirstName} {LastName}"; return _fullName; } }}This implementation works because theFirstName andLastName properties are readonly. People can change their name. Updating theFirstName andLastName properties to allowset accessors requires you to invalidate any cached value forfullName. You modify theset accessors of theFirstName andLastName property so thefullName field is calculated again:
public class Person{ private string? _firstName; public string? FirstName { get => _firstName; set { _firstName = value; _fullName = null; } } private string? _lastName; public string? LastName { get => _lastName; set { _lastName = value; _fullName = null; } } private string? _fullName; public string FullName { get { if (_fullName is null) _fullName = $"{FirstName} {LastName}"; return _fullName; } }}This final version evaluates theFullName property only when needed. The previously calculated version is used if valid. Otherwise, the calculation updates the cached value. Developers using this class don't need to know the details of the implementation. None of these internal changes affect the use of the Person object.
Beginning with C# 13, you can createpartial properties inpartial classes. The implementing declaration for apartial property can't be an automatically implemented property. An automatically implemented property uses the same syntax as a declaring partial property declaration.
Properties are a form of smart fields in a class or object. From outside the object, they appear like fields in the object. However, properties can be implemented using the full palette of C# functionality. You can provide validation, different accessibility, lazy evaluation, or any requirements your scenarios need.
set orinit accessor is assigning.get and aset accessor),read-only (they have aget accessor but noset accessor), orwrite-only (they have aset accessor, but noget accessor). Write-only properties are rare.For more information, seeProperties in theC# Language Specification. The language specification is the definitive source for C# syntax and usage.
Was this page helpful?
Need help with this topic?
Want to try using Ask Learn to clarify or guide you through this topic?
Was this page helpful?
Want to try using Ask Learn to clarify or guide you through this topic?