0% found this document useful (0 votes)
8 views9 pages

Code Listings 2

Uploaded by

mbsysde
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views9 pages

Code Listings 2

Uploaded by

mbsysde
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 9

11/16/24, 10:56 PM C# in a Nutshell - Code Listings

Chapter 3 - Creating Types in C#


Classes
Fields

// A field is a variable that is a member of a class or struct.

var o = new Octopus();


o.Age.Dump();

class Octopus
{
string name;
public int Age = 10;
static readonly int legs = 8, eyes = 1;
}

Fields - readonly

// Readonly fields let you create *immutable* classes.

var o = new Octopus ("Jack");


o.Name.Dump();
o.Legs = 20; // Compile-time error

class Octopus
{
public readonly string Name;
public readonly int Legs = 8;

public Octopus (string name)


{
Name = name;
}
}

Constants - scoped to class

// Constants are factored out at compile-time and baked into the calling site.

Test.Message.Dump();

public class Test


{
public const string Message = "Hello World";
}

Constants - scoped to method

// Here, the calculation is performed at compile-time:

const double twoPI = 2 * System.Math.PI;


twoPI.Dump();

Methods - Expression-bodied

// Foo1 and Foo2 are equivalent:

Foo1 (10).Dump();
Foo2 (10).Dump();

int Foo1 (int x) { return x * 2; }


int Foo2 (int x) => x * 2;

Local methods

void Main()
{
WriteCubes();
}

void WriteCubes()
{
Console.WriteLine (Cube (3));
Console.WriteLine (Cube (4));
Console.WriteLine (Cube (5));

int Cube (int value) => value * value * value;


}

Local methods - with top-level statements

https://w w w .albahari.com/nutshell/E12-CH03.aspx 1/9


11/16/24, 10:56 PM C# in a Nutshell - Code Listings
// When you use top-level statements, your methods are implicitly local.
// We can verify this by trying to access a variable outside the method:

int x = 3;
Foo();

// Foo is a local method


void Foo() => Console.WriteLine (x); // We can access x

Methods - Overloading

// We can overload Foo as follows:

void Foo (int x) { "int".Dump(); }


void Foo (double x) { "double".Dump(); }
void Foo (int x, float y) { "int, float".Dump(); }
void Foo (float x, int y) { "float, int".Dump(); }

// We have to use a Main() method here to test this,


// because methods in top-level statements are *local methods*
// which cannot be overloaded.

void Main()
{
Foo (123); // int
Foo (123.0); // double
Foo (123, 123F); // int, float
Foo (123F, 123); // float, int
}

Methods - Illegal Overloading

// The following overloads are prohibited:

void Foo (int x);


float Foo (int x); // Compile-time error

void Goo (int[] x);


void Goo (params int[] x); // Compile-time error

void Hoo (int x);


void Hoo (ref int x); // OK so far
void Hoo (out int x); // Compile-time error

void Main() {}

Constructors

Panda p = new Panda ("Petey"); // Call constructor

public class Panda


{
string name; // Define field
public Panda (string n) // Define constructor
{
name = n; // Initialization code (set up field)
}
}

Constructors - Overloading

// You can also overload constructors.


// Note the use of the "this" keyword to call another constructor:

new Wine (78).Dump();


new Wine (78, 2001).Dump();

public class Wine


{
public decimal Price;
public int Year;
public Wine (decimal price) => Price = price;
public Wine (decimal price, int year) : this (price) => Year = year;
}

Constructors - Nonpublic

// A common reason to have a nonpublic constructor is to control instance creation via a


// static method call:

Class1 c1 = Class1.Create(); // OK
Class1 c2 = new Class1(); // Error: Will not compile

public class Class1


{
Class1() { } // Private constructor

public static Class1 Create()

https://w w w .albahari.com/nutshell/E12-CH03.aspx 2/9


11/16/24, 10:56 PM C# in a Nutshell - Code Listings
{
// Perform custom logic here to create & configure an instance of Class1
/* ... */
return new Class1();
}
}

Deconstructors

// To call the deconstructor, we use the following special syntax:


var rect = new Rectangle (3, 4);
(float width, float height) = rect; // Deconstruction
Console.WriteLine (width + " " + height); // 3 4

// We can also use implicit typing:


var (x, y) = rect; // Deconstruction
Console.WriteLine (x + " " + y);

// If the variables already exist, we can do a *deconstructing assignment*:


(x, y) = rect;
Console.WriteLine (x + " " + y);

// The following mix-and-match is permitted, from C# 10:


double x1 = 0;
(x1, double y2) = rect;

class Rectangle
{
public readonly float Width, Height;

public Rectangle (float width, float height)


{
Width = width;
Height = height;
}

public void Deconstruct (out float width, out float height)


{
width = Width;
height = Height;
}
}

Object Initializers

// Fields or properties can be initialized in a single statement directly after construction:

// Object initialization syntax. Note that we can still specify constructor arguments:

Bunny b1 = new Bunny { Name="Bo", LikesCarrots=true, LikesHumans=false };


Bunny b2 = new Bunny ("Bo") { LikesCarrots=true, LikesHumans=false };

b1.Dump(); b2.Dump();

public class Bunny


{
public string Name;
public bool LikesCarrots;
public bool LikesHumans;

public Bunny () {}
public Bunny (string n) { Name = n; }
}

Object Initializer Alternative - Optional Parameters

// Instead of using object initializers, we could make Bunny’s constructor accept optional parameters.
// This has both pros and cons (see book):

Bunny b = new Bunny (


name: "Bo",
likesCarrots: true);

b.Dump();

public class Bunny


{
public string Name;
public bool LikesCarrots;
public bool LikesHumans;

public Bunny (
string name,
bool likesCarrots = false,
bool likesHumans = false)
{
Name = name;
LikesCarrots = likesCarrots;
LikesHumans = likesHumans;

https://w w w .albahari.com/nutshell/E12-CH03.aspx 3/9


11/16/24, 10:56 PM C# in a Nutshell - Code Listings
}
}

The this Reference

// The this reference refers to the instance itself:

new Panda().Marry (new Panda());

public class Panda


{
public Panda Mate;

public void Marry (Panda partner)


{
Mate = partner;
partner.Mate = this;
}
}

Properties

// Properties look like fields from the outside but internally, they contain logic, like methods:

var stock = new Stock();


stock.CurrentPrice = 123.45M;
stock.CurrentPrice.Dump();

var stock2 = new Stock { CurrentPrice = 83.12M };


stock2.CurrentPrice.Dump();

public class Stock


{
decimal currentPrice; // The private "backing" field

public decimal CurrentPrice // The public property


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

Properties - calculated & read-only

// The Worth Property is a read-only calculated property.

var stock = new Stock { CurrentPrice = 50, SharesOwned = 100 };


stock.Worth.Dump();

public class Stock


{
decimal currentPrice; // The private "backing" field
public decimal CurrentPrice // The public property
{
get { return currentPrice; } set { currentPrice = value; }
}

decimal sharesOwned; // The private "backing" field


public decimal SharesOwned // The public property
{
get { return sharesOwned; } set { sharesOwned = value; }
}

public decimal Worth


{
get { return currentPrice * sharesOwned; }
}
}

Properties - expression-bodied

// The Worth Property is now an expression-bodied property.

var stock = new Stock { CurrentPrice = 50, SharesOwned = 100 };


stock.Worth.Dump();

public class Stock


{
decimal currentPrice; // The private "backing" field
public decimal CurrentPrice // The public property
{
get { return currentPrice; } set { currentPrice = value; }
}

decimal sharesOwned; // The private "backing" field


public decimal SharesOwned // The public property
{
get { return sharesOwned; } set { sharesOwned = value; }
}

https://w w w .albahari.com/nutshell/E12-CH03.aspx 4/9


11/16/24, 10:56 PM C# in a Nutshell - Code Listings
public decimal Worth => currentPrice * sharesOwned; // Expression-bodied property

// From C# 7, we can take this further, and write both the get and set accessors in
// expression-bodied syntax:
public decimal Worth2
{
get => currentPrice * sharesOwned;
set => sharesOwned = value / currentPrice;
}

Automatic Properties

// Here's the preceding example rewritten with two automatic properties:

var stock = new Stock { CurrentPrice = 50, SharesOwned = 100 };


stock.Worth.Dump();

public class Stock


{
public decimal CurrentPrice { get; set; } // Automatic property
public decimal SharesOwned { get; set; } // Automatic property

public decimal Worth


{
get { return CurrentPrice * SharesOwned; }
}
}

Property Initializers

var stock = new Stock();


stock.CurrentPrice.Dump();
stock.Maximum.Dump();

public class Stock


{
public decimal CurrentPrice { get; set; } = 123;
public int Maximum { get; } = 999;
}

Properties - get & set accessibility

// In this example, the set accessors are private while the get accessors are public:

new Foo { X = 5 }; // Will not compile - X has a private set accessor.

public class Foo


{
private decimal x;
public decimal X
{
get { return x; }
private set { x = Math.Round (value, 2); }
}

public int Auto { get; private set; } // Automatic property


}

Indexers

// You can implement custom indexers with the this keyword:

Sentence s = new Sentence();


Console.WriteLine (s[3]); // fox
s[3] = "kangaroo";
Console.WriteLine (s[3]); // kangaroo

// Test the indexers that use C#'s Indices and Ranges:

Console.WriteLine (s [^1]); // fox


string[] firstTwoWords = s [..2].Dump(); // (The, quick)

class Sentence
{
string[] words = "The quick brown fox".Split();

public string this [int wordNum] // indexer


{
get { return words [wordNum]; }
set { words [wordNum] = value; }
}

// In C# 8, we can also define indexers that use the Index & Range types:
public string this [Index index] => words [index];
public string[] this [Range range] => words [range];

https://w w w .albahari.com/nutshell/E12-CH03.aspx 5/9


11/16/24, 10:56 PM C# in a Nutshell - Code Listings
Primary Constructors

// From C# 12, you can include a parameter list directly after a class (or struct) declaration.
// This instructs the compiler to automatically build a primary constructor using the primary
// constructor parameters (firstName and lastName).

Person p = new Person ("Alice", "Jones");


p.Print(); // Alice Jones

class Person (string firstName, string lastName)


{
public void Print() => Console.WriteLine (firstName + " " + lastName);
}

// See also query://../Inheritance/Inheritance_with_primary_constructors

Primary Constructors - additional constructors

Person p = new Person ("Alice", "Jones", 33);


p.Print(); // Alice Jones

class Person (string firstName, string lastName)


{
int _age;

// The constructor that C# builds is called primary because any additional constructors
// that you choose to (explicitly) write must invoke it:

public Person (string firstName, string lastName, int age)


: this (firstName, lastName) // Must call the primary constructor
{
_age = age;
}

public void Print() => Console.WriteLine (firstName + " " + lastName + " " + _age);
}

// See also query://../Inheritance/Inheritance_with_primary_constructors

Primary Constructors and initializers

// The accessibility of primary constructor parameters extends to field and property initializers.
// In the following example, we use field and property initializers to assign firstName to a public
// field, and lastName to a public property:

Person p = new Person ("Alice", "Jones");


p.Dump();

class Person (string firstName, string lastName)


{
public readonly string FirstName = firstName; // Field
public string LastName { get; } = lastName; // Property
}

Primary Constructors - masking

// Fields (or properties) can reuse primary constructor parameter names:

Person p = new Person ("Alice", "Jones");


p.Print();

class Person (string firstName, string lastName)


{
// In this scenario, the field or property takes precedence, thereby masking
// the primary constructor parameter, except on the righthand side of field and
// property initializers:
readonly string firstName = firstName;
readonly string lastName = lastName;

public void Print() => Console.WriteLine (firstName + " " + lastName);


}

Primary Constructors - validating

new Person1 ("Alice", "Jones").Print(); // Alice Jones


new Person2 ("Alice", "Jones").Print(); // Alice JONES
var p3 = new Person3 ("Alice", null); // throws ArgumentNullException

class Person1 (string firstName, string lastName)


{
// Sometimes it’s useful to perform computation in field initializers:
public readonly string FullName = firstName + " " + lastName;

public void Print() => Console.WriteLine (FullName);


}

class Person2 (string firstName, string lastName)


{
// Save an uppercase version of lastName to a field of the same name

https://w w w .albahari.com/nutshell/E12-CH03.aspx 6/9


11/16/24, 10:56 PM C# in a Nutshell - Code Listings
// (masking the original value):
readonly string lastName = lastName.ToUpper();

public void Print() => Console.WriteLine (firstName + " " + lastName);


}

class Person3 (string firstName, string lastName)


{
// Validate lastName upon construction, ensuring that it cannot be null:
readonly string lastName = (lastName == null)
? throw new ArgumentNullException ("lastName")
: lastName;

public void Print() => Console.WriteLine (firstName + " " + lastName);


}

Static Constructors

// A static constructor executes once per type, rather than once per instance:

// Type is initialized only once


new Test();
new Test();
new Test();

class Test
{
static Test()
{
Console.WriteLine ("Type Initialized");
}
}

Static Constructors & Field Initialization Order

// Static field initializers run just before the static constructor is called:

Foo.X.Dump ("X"); // 0
Foo.Y.Dump ("Y"); // 3

class Foo
{
public static int X = Y; // 0
public static int Y = 3; // 3
}

Static Constructors & Field Initialization Order (Constructor Call)

// Another way to go awry:

Console.WriteLine (Foo.X); // 3

Util.NewProcess = true; // Force LINQPad to create new process on each run.

class Foo
{
public static Foo Instance = new Foo();
public static int X = 3;

Foo() => Console.WriteLine (X); // 0


}

Partial Types

// Partial types allow a type definition to be split—typically across multiple files:

new PaymentForm { X = 3, Y = 4 }.Dump();

partial class PaymentForm { public int X; }


partial class PaymentForm { public int Y; }

Partial Methods

// A partial type may contain partial methods. These let an auto-generated partial type
// provide customizable hooks for manual authoring.

var paymentForm = new PaymentForm (50);

partial class PaymentForm // In auto-generated file


{
public PaymentForm (decimal amount)
{
ValidatePayment (amount);
// ...
}

partial void ValidatePayment (decimal amount);


}

https://w w w .albahari.com/nutshell/E12-CH03.aspx 7/9


11/16/24, 10:56 PM C# in a Nutshell - Code Listings
partial class PaymentForm // In hand-authored file
{
partial void ValidatePayment (decimal amount)
{
if (amount < 100)
throw new ArgumentOutOfRangeException ("amount", "Amount too low!");
}
}

Extended Partial Methods

// The presence of an accessiblity modifier on a partial method denotes an 'extended partial method'.
// Extended partial methods *must* have implementations:

public partial class Test


{
public partial void M1(); // Extended partial method
private partial void M2(); // Extended partial method

public partial bool IsValid (string identifier);


internal partial bool TryParse (string number, out int result);
}

public partial class Test


{
public partial void M1() { }
private partial void M2() {}

public partial bool IsValid (string identifier) => !string.IsNullOrEmpty (identifier);


internal partial bool TryParse (string number, out int result) => int.TryParse (number, out result);
}

The nameof operator

int count = 123;


nameof (count).Dump ("count");

nameof (StringBuilder.Length).Dump ("Length property on StringBuilder");

(nameof (StringBuilder) + "." + nameof (StringBuilder.Length)).Dump ("StringBuilder.Length");

Inheritance

The object Type

Structs

Access Modifiers

Interfaces

Enums

Nested Types

Generics

C# 12
in a Nutshell
About the Book

Code Listings
C# 12 in a Nutshell
C# 10 in a Nutshell
C# 9.0 in a Nutshell
C# 8.0 in a Nutshell
C# 7.0 in a Nutshell

https://w w w .albahari.com/nutshell/E12-CH03.aspx 8/9


11/16/24, 10:56 PM C# in a Nutshell - Code Listings

Extras

Contact

Buy print or Kindle edition

Buy PDF edition

Read via O'Reilly subscription

https://w w w .albahari.com/nutshell/E12-CH03.aspx 9/9

You might also like