Properties provide controlled access to data; at the most basic, it can just mean encapsulating a field (public fields are not recommended), which the compiler can make easy for you:
public int Foo {get;set;} // the compiler handles the field for you
You could, however, use the property to enforce logic or handle side effects:
private int foo;
public int Foo {
get { return foo; }
set {
if(value < 0) throw new ArgumentOutOfRangeException();
if(value != foo) {
foo = value;
OnFooChanged(); // fire event notification for UI bindings
}
}
}
Other common options are lazy-loading, calculated members, proxied members, etc.
You can also change the accessibility, for example:
public int Foo { get; protected set; }
which can only be assigned by the type and subclasses, not by unrelated code. It could also only have a get or set.
Basically, properties act as a more formal version of a get/set pair of methods, making it much easier to talk about "Foo", rather than "get_Foo"/"set_Foo" etc (for two-way binding).
Unlike fields, properties can also be advertised on interfaces, which is essential for interface-based code