public
Allows a field or method to be used / called from outside the class.
private
Prevents a field or method to be used / called from outside the class. If no accessibility level is provided it is defaulted to private. Fields should generally be private as a rule of thumb.
internal
Like public, but limited to a project. When creating a type itself the default accessibility option is internal.
readonly
The readonly modifier is used in conjunction with an access level and is used to create an immutable field. They can be assigned a value as an initializer or in a constructor, but nowhere else:
public class Player
{
private readonly string _name;
public Player(string name)
{
_name = name;
}
}
required
public class Person
{
public required string LastName { get; set; }
public required string FirstName { get; set; }
var p1 = new Person(); // Error! Required properties not set
var p2 = new Person() { FirstName = "Grace", LastName = "Hopper" };
}
static
When using Console, Convert, and Math we do not need to call
new Console() first. Members of a class can be marked static which makes
them owned by the type / class itself rather than an individual object. If an
entire class is marked static, as is the case with Console and the others, all
of its members must be marked static.
This is used to create "global" like variables, but tied to a specific class:
public class Score
{
private static readonly int PointThreshold = 1000; // Points needed to win.
private static readonly int LevelThreshold = 4; // Level needed to win.
}
Static fields are usually named with UpperCamelCase rather than _lowerCamelCase.
A static constructor can also be created, which is not called directly and
cannot have parameters, but instead runs automatically the first time the class
is used. It's a bit like go's init() function.
protected
The protected modifier allows usage from within the class or any derived classes.
virtual and override
Allows derived classes to "override" the implementation of a given method. This is one of the main ways to achieve polymorphism in c#. Take this base class of a chess piece for example:
public class ChessPiece
{
public int Row { get; set; }
public int Column { get; set; }
public virtual bool IsLegalMove(int row, int column)
{
return IsOnBoard(row, column) && !IsCurrentLocation(row, column);
}
public bool IsOnBoard(int row, int column)
{
return row >= 0 && row < 8 && column >= 0 && column < 8;
}
public bool IsCurrentLocation(int row, int column)
{
return row == Row && column == Column;
}
}
Because IsLegalMove is a virtual method we can override the implementation for
out KingPiece derived class:
public class KingPiece : ChessPiece
{
public override bool IsLegalMove(int row, int column)
{
if (!base.IsLegalMove(row, column)) return false;
if (Math.Abs(row - Row) > 1) return false;
if (Math.Abs(column - Column) > 1) return false;
return true;
}
}