Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a710a90
draft
tdykstra Feb 18, 2021
16e5a5d
uncomment
tdykstra Feb 25, 2021
d17fe78
fix metadata
tdykstra Feb 25, 2021
f892814
fix sample output
tdykstra Feb 25, 2021
0d8d639
proofread and acrolinx
tdykstra Feb 25, 2021
d900110
Update docs/csharp/language-reference/builtin-types/record.md
tdykstra Feb 25, 2021
7b67707
Update docs/csharp/language-reference/builtin-types/record.md
tdykstra Feb 25, 2021
b01d4b0
Update docs/csharp/language-reference/builtin-types/record.md
tdykstra Feb 25, 2021
0fe9fc2
Update docs/csharp/language-reference/builtin-types/record.md
tdykstra Feb 25, 2021
8d58f4e
Update docs/csharp/language-reference/builtin-types/record.md
tdykstra Feb 25, 2021
101f20f
Update docs/csharp/language-reference/builtin-types/record.md
tdykstra Feb 25, 2021
4b468a8
Update docs/csharp/language-reference/builtin-types/record.md
tdykstra Feb 25, 2021
55445cb
Update docs/csharp/language-reference/builtin-types/record.md
tdykstra Feb 25, 2021
048ad75
move iequatable to equals bullet
tdykstra Feb 25, 2021
357c5dd
ef core
tdykstra Feb 25, 2021
8597f88
classes and structs doc
tdykstra Feb 26, 2021
87f5885
add notes about records
tdykstra Feb 26, 2021
70d4aee
Update docs/csharp/language-reference/builtin-types/record.md
tdykstra Feb 26, 2021
dbd5d41
programming guide article
tdykstra Feb 27, 2021
027454d
Merge branch 'records' of https://github.com/tdykstra/dotnet-docs int…
tdykstra Feb 27, 2021
8d83ff6
mention records in more places
tdykstra Mar 1, 2021
5b27482
minor corrections
tdykstra Mar 1, 2021
c828132
add records
tdykstra Mar 2, 2021
198ac48
fix links
tdykstra Mar 4, 2021
b41844f
proofread staging
tdykstra Mar 4, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/csharp/basic-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ C# provides a standard set of built-in numeric types to represent integers, floa

## Custom types

You use the [struct](language-reference/builtin-types/struct.md), [class](language-reference/keywords/class.md), [interface](language-reference/keywords/interface.md), and [enum](language-reference/builtin-types/enum.md) constructs to create your own custom types. The .NET class library itself is a collection of custom types provided by Microsoft that you can use in your own applications. By default, the most frequently used types in the class library are available in any C# program. Others become available only when you explicitly add a project reference to the assembly in which they are defined. After the compiler has a reference to the assembly, you can declare variables (and constants) of the types declared in that assembly in source code.
You use the [struct](language-reference/builtin-types/struct.md), [class](language-reference/keywords/class.md), [record](language-reference/builtin-types/record.md), [interface](language-reference/keywords/interface.md), and [enum](language-reference/builtin-types/enum.md) constructs to create your own custom types. The .NET class library itself is a collection of custom types provided by Microsoft that you can use in your own applications. By default, the most frequently used types in the class library are available in any C# program. Others become available only when you explicitly add a project reference to the assembly in which they are defined. After the compiler has a reference to the assembly, you can declare variables (and constants) of the types declared in that assembly in source code.

## Generic types

Expand Down
4 changes: 2 additions & 2 deletions docs/csharp/how-to/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ There are several tips and tricks that are common C# developer practices:
- Even C# programmers may want to [use the `My` namespace from Visual Basic](../programming-guide/namespaces/how-to-use-the-my-namespace.md).
- [Create a new method for an `enum` type using extension methods](../programming-guide/classes-and-structs/how-to-create-a-new-method-for-an-enumeration.md).

### Class and struct members
### Class, record, and struct members

You create classes and structs to implement your program. These techniques are commonly used when writing classes or structs.
You create classes, records, and structs to implement your program. These techniques are commonly used when writing classes, records, or structs.

- [Declare auto implemented properties](../programming-guide/classes-and-structs/how-to-implement-a-lightweight-class-with-auto-implemented-properties.md).
- [Declare and use read/write properties](../programming-guide/classes-and-structs/how-to-declare-and-use-read-write-properties.md).
Expand Down
208 changes: 208 additions & 0 deletions docs/csharp/language-reference/builtin-types/record.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ static void Main(string[] args)
StructType.Examples();
Console.WriteLine();

Console.WriteLine("========== Records ===============");
RecordType.Examples();
Console.WriteLine();

Console.WriteLine("===== Nullable reference types ===");
NullableReferenceTypes.Examples();
Console.WriteLine();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,359 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace builtin_types
{
public static class RecordType
{
public static void Examples()
{
instantiatepositional.Example.Main();
positionalwithmanualproperty.Example.Main();
shallowimmutability.Example.Main();
equality.Example.Main();
withexpressions.Example.Main();
recordinheritancetostringdefault.Example.Main();
recordinheritancepositional.Example.Main();
recordinheritanceequality.Example.Main();
recordinheritancewithexpression.Example.Main();
recordinheritancetostring.Example.Main();
recordinheritanceprintmembers.Example.Main();
recordinheritancedeconstructor.Example.Main();
}
// <PositionalRecord>
public record Person(string FirstName, string LastName);
// </PositionalRecord>
}

public static class ImmutableRecordType
{
// <ImmutableRecord>
public record Person
{
public string FirstName { get; init; }
public string LastName { get; init; }
};
// </ImmutableRecord>
}

public static class MutableRecordType
{
// <MutableRecord>
public record Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
};
// </MutableRecord>
}

public static class MixedSyntax
{
// <MixedSyntax>
public record Person(string FirstName, string LastName)
{
public string[] PhoneNumbers { get; init; }
};
// </MixedSyntax>
}

namespace instantiatepositional
{
public static class Example
{
// <InstantiatePositional>
public record Person(string FirstName, string LastName);

public static void Main()
{
Person person = new("Nancy", "Davolio");
Console.WriteLine(person);
// output: Person { FirstName = Nancy, LastName = Davolio }
}
// </InstantiatePositional>
}
}

namespace positionalwithmanualproperty
{
public static class Example
{
// <PositionalWithManualProperty>
public record Person(string FirstName, string LastName)
{
internal string FirstName { get; init; } = FirstName;
}

public static void Main()
{
Person person = new("Nancy", "Davolio");
Console.WriteLine(person.FirstName); //output: Nancy
}
// </PositionalWithManualProperty>
}
}

namespace shallowimmutability
{
public static class Example
{
// <ShallowImmutability>
public record Person(string FirstName, string LastName, string[] PhoneNumbers);

public static void Main()
{
Person person = new("Nancy", "Davolio", new string[1] { "555-1234" });
Console.WriteLine(person.PhoneNumbers[0]); // output: 555-1234

person.PhoneNumbers[0] = "555-6789";
Console.WriteLine(person.PhoneNumbers[0]); // output: 555-6789
}
// </ShallowImmutability>
}
}
namespace equality
{
public static class Example
{
// <Equality>
public record Person(string FirstName, string LastName, string[] PhoneNumbers);

public static void Main()
{
var phoneNumbers = new string[2];
Person person1 = new("Nancy", "Davolio", phoneNumbers);
Person person2 = new("Nancy", "Davolio", phoneNumbers);
Console.WriteLine(person1 == person2); // output: True

person1.PhoneNumbers[0] = "555-1234";
Console.WriteLine(person1 == person2); // output: True

Console.WriteLine(ReferenceEquals(person1, person2)); // output: False
}
// </Equality>
}
}

namespace withexpressions
{
public static class Example
{
// <WithExpressions>
public record Person(string FirstName, string LastName)
{
public string[] PhoneNumbers { get; init; }
}

public static void Main()
{
Person person1 = new("Nancy", "Davolio") { PhoneNumbers = new string[1] };
Console.WriteLine(person1);
// output: Person { FirstName = Nancy, LastName = Davolio, PhoneNumbers = System.String[] }

Person person2 = person1 with { FirstName = "John" };
Console.WriteLine(person2);
// output: Person { FirstName = John, LastName = Davolio, PhoneNumbers = System.String[] }
Console.WriteLine(person1 == person2); // output: False

person2 = person1 with { PhoneNumbers = new string[1] };
Console.WriteLine(person2);
// output: Person { FirstName = Nancy, LastName = Davolio, PhoneNumbers = System.String[] }
Console.WriteLine(person1 == person2); // output: False

person2 = person1 with { };
Console.WriteLine(person1 == person2); // output: True
}
// </WithExpressions>
}
}

namespace recordinheritancepositional
{
public static class Example
{
// <PositionalInheritance>
public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public static void Main()
{
Person teacher = new Teacher("Nancy", "Davolio", 3);
Console.WriteLine(teacher);
// output: Teacher { FirstName = Nancy, LastName = Davolio, Grade = 3 }
}
// </PositionalInheritance>
}
}

namespace recordinheritanceequality
{
public static class Example
{
// <InheritanceEquality>
public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public record Student(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public static void Main()
{
Person teacher = new Teacher("Nancy", "Davolio", 3);
Person student = new Student("Nancy", "Davolio", 3);
Console.WriteLine(teacher == student); // output: False

Student student2 = new Student("Nancy", "Davolio", 3);
Console.WriteLine(student2 == student); // output: True
}
// </InheritanceEquality>
}
}

namespace recordinheritancetostringdefault
{
public static class Example
{
public abstract record Person(string FirstName, string LastName, string[] PhoneNumbers);
public record Teacher(string FirstName, string LastName, string[] PhoneNumbers, int Grade)
: Person(FirstName, LastName, PhoneNumbers)
{
// <ToStringOverrideDefault>
public override string ToString()
{
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.Append("Teacher"); // type name
stringBuilder.Append(" { ");
if (PrintMembers(stringBuilder))
{
stringBuilder.Append(" ");
}
stringBuilder.Append("}");
return stringBuilder.ToString();
}
// </ToStringOverrideDefault>
};

public static void Main()
{
Person teacher = new Teacher("Nancy", "Davolio", new string[2] { "555-1234", "555-6789" }, 3);
Console.WriteLine(teacher);
}
}
}

namespace recordinheritanceprintmembers
{
public static class Example
{
// <PrintMembersImplementation>
public abstract record Person(string FirstName, string LastName, string[] PhoneNumbers)
{
protected virtual bool PrintMembers(StringBuilder stringBuilder)
{
stringBuilder.Append($"FirstName = {FirstName}, LastName = {LastName}, ");
stringBuilder.Append($"PhoneNumber1 = {PhoneNumbers[0]}, PhoneNumber2 = {PhoneNumbers[1]}");
return true;
}
}

public record Teacher(string FirstName, string LastName, string[] PhoneNumbers, int Grade)
: Person(FirstName, LastName, PhoneNumbers)
{
protected override bool PrintMembers(StringBuilder stringBuilder)
{
if (base.PrintMembers(stringBuilder))
{
stringBuilder.Append(", ");
};
stringBuilder.Append($"Grade = {Grade}");
return true;
}
};

public static void Main()
{
Person teacher = new Teacher("Nancy", "Davolio", new string[2] { "555-1234", "555-6789" }, 3);
Console.WriteLine(teacher);
// output: Teacher { FirstName = Nancy, LastName = Davolio, PhoneNumber1 = 555-1234, PhoneNumber2 = 555-6789, Grade = 3 }
}
// </PrintMembersImplementation>
}
}

namespace recordinheritancetostring
{
public static class Example
{
// <ToStringInheritance>
public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public record Student(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);

public static void Main()
{
Person teacher = new Teacher("Nancy", "Davolio", 3);
Console.WriteLine(teacher);
// output: Teacher { FirstName = Nancy, LastName = Davolio, Grade = 3 }
}
// </ToStringInheritance>
}
}

namespace recordinheritancedeconstructor
{
public static class Example
{
// <DeconstructorInheritance>
public abstract record Person(string FirstName, string LastName);
public record Teacher(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);
public record Student(string FirstName, string LastName, int Grade)
: Person(FirstName, LastName);

public static void Main()
{
Person teacher = new Teacher("Nancy", "Davolio", 3);
var (firstName, lastName) = teacher; // Doesn't deconstruct Grade
Console.WriteLine($"{firstName}, {lastName}");// output: Nancy, Davolio

var (fName, lName, grade) = (Teacher)teacher;
Console.WriteLine($"{fName}, {lName}, {grade}");// output: Nancy, Davolio, 3
}
// </DeconstructorInheritance>
}
}

namespace recordinheritancewithexpression
{
public static class Example
{
// <WithExpressionInheritance>
public record Point(int X, int Y)
{
public int Zbase { get; set; }
};
public record NamedPoint(string Name, int X, int Y) : Point(X, Y)
{
public int Zderived { get; set; }
};

public static void Main()
{
Point p1 = new NamedPoint("A", 1, 2) { Zbase = 3, Zderived = 4 };

Point p2 = p1 with { X = 5, Y = 6, Zbase = 7 }; // Can't set Name or Zderived
Console.WriteLine(p2 is NamedPoint); // output: True
Console.WriteLine(p2);
// output: NamedPoint { X = 5, Y = 6, Zbase = 7, Name = A, Zderived = 4 }

Point p3 = (NamedPoint)p1 with { Name = "B", X = 5, Y = 6, Zbase = 7, Zderived = 8 };
Console.WriteLine(p3);
// output: NamedPoint { X = 5, Y = 6, Zbase = 7, Name = B, Zderived = 8 }
}
// </WithExpressionInheritance>
}
}
}
Loading