Lesson7 Report
Lesson7 Report
Declaring Fields
A field is declared within a class but outside any methods,
constructors, or properties. Fields are typically private to
encapsulate the class's data, but they can be made public or
protected as needed.
1. Properties
Properties are class members that provide a flexible mechanism for reading,
writing, or computing the values of private fields. Properties allow you to
control access, perform validation, or even compute values on-the-fly, making
them ideal for encapsulating class data.
Example:
Read-Only and Write-Only
Properties
Properties can also be read-only or write-only, depending on whether they include
only a get
or set accessor.
Example of a Read-Only
Property:
Example:
Indexers
Indexers allow instances of a class to be indexed just like arrays. They are useful
for classes that represent collections or have data that can logically be accessed
via an index.
Syntax of an Indexer: An indexer is defined with the this keyword, which allows
instances of
the class to be indexed.
Indexers
Example:
Combining Properties and
Indexers
Properties and indexers provide safe, controlled access to data within objects:
•Properties control individual values with potential validation.
These features help encapsulate data, enforce business rules, and allow for the
logical
structuring of how data is accessed and modified.
06
Pattern Matching
with Objects
Pattern Matching with
Pattern matching in C# allowsObjects
you to inspect an object's type and structure
directly in
expressions, simplifying conditional code by matching objects to patterns.
Introduced in C# 7 and expanded in later versions, pattern matching is
especially powerful with objects, enabling concise code for checking types,
properties, or specific values within complex conditions.
Types of Pattern Matching with
1. Pattern Matching with is. Objects
2. Property Pattern Matching.
3. Positional Pattern Matching.
4. when Clause in Pattern Matching
5. Combining Patterns
1. Pattern Matching with is.
The is pattern matches the type of an object, simplifying the as cast followed by a
null check.
This helps when you need to determine if an object is of a certain type and then
Example:
work with it.
Example:
Example:
Summary
Example:
In this example:
• The Person record has two properties, FirstName
and LastName .
• Person automatically includes value-based
equality, Tostring, and GetHashcode methods
based on the property values.
Using a Positional Records
• Explanation: The with expression creates a new Person record, copying all
values from
originalperson except for LastName , which is set to "Smith".
Equality and Comparison
Records use value-based equality, meaning two records are considered equal
if their property values are the same, unlike regular classes, which compare
by reference.
Example:
In this case, personA and personB are equal because their FirstName and
LastName values are identical, even though they are two different instances.
Inheritance with Records
Records support inheritance, and derived records also maintain immutability
and value-based equality by default.
Example:
In this setup:
• Animal is the base record with Name and Age properties.
• Dog inherits from Animal and adds a Breed property.
2. Delegates: Delegates are types that define the signature of the method
that can be called
by the event.
Step 5: Build and Run the Solution
1. Set myconsoleApp as the Startup Project. Right-click on MyconsoleApp in
Solution Explorer
and select Set as Startup Project.
2. Press F5 or Ctrl + F5 to build and run the console application.
Summary
By setting up the class library and referencing it in the console application:
2. Code Reusability: Generics allow you to write code that works with any
data type, reducing redundancy.
In this
example:
• GenericClass<T> is a generic class with a
type parameter T .
In this
• example:
MyList<T> can store any type
(e.g., int, string) in a type-safe way.
In this
example:
• The PrintArray method works with any array type ( int[] ,
string[] , etc.) while
maintaining type safety.
Common Constraints
• where T : IComparable : Ensures T implements the IComparable
interface.
Generics make your code safer, more flexible, and reusable by allowing it to
work with any data type while enforcing type safety. Here's a quick summary
of their benefits:
• Code Reusability: Allows you to write code once and use it with various
data types.
In these classes:
In this example:
• Value types store data directly. • Reference types store a reference (or
• They are typically allocated on the pointer) to the actual data, not the data
stack (a region of memory that itself.
stores variables with a fixed scope). • They are allocated on the heap (a region
• Examples include primitive types of memory for dynamically allocated objects
like int, double, bool, struct, and with variable lifetimes).
enum . • Examples include classes, arrays, string,
• Value types have a fixed size, so delegates, and interfaces.
they are stored directly in memory • The heap is managed by the garbage
locations. collector, which frees memory that is no
Key Differences Between Value Types and
Reference Types
Assignment Behavior: Scope and Lifetime:
• For value types, when you assign • Value types are destroyed when they
one variable to another, a copy of the go out of scope (e.g., after a method
value is made. completes).
• For reference types, when you
assign one variable to another, only • Reference types stay in memory
the reference (pointer) is copied, so until the garbage collector determines
both variables point to the same that they are no longer in use.
memory location.
Memory Allocation:
• Value types are stored in stack
memory and have a smaller memory
footprint, making them quick to
allocate and deallocate.
• Reference types are stored in heap
memory, which is slower to allocate
and deallocate. However, they can
have complex structures and larger
Examples of Value Type and
Reference Type Behavior
3. out keyword:
• Also allows a variable to be passed
by reference but does not require it to
be initialized beforehand.
• The method must assign a value to
the parameter before it returns.
Using ref and out Keywords
using ref and out is particularly helpful for modifying value types without
creating unnecessary copies, but it should be used sparingly as it can make
code harder to read.
Choosing Between Value Types and
Reference Types
• Use value types for small, simple • Use reference types for more complex
data (e.g., numbers, structs) where data structures that need to be shared
performance is critical. across multiple locations in the program or
may grow in size.
In this example:
• myDog can call Eat (from Animal), • This setup illustrates polymorphism,
Bark (specific to Dog) and the where a derived class can change or
overridden Makesound method. extend the behavior of the base
class.
Access Modifiers and Inheritance
Usage:
Abstract Classes and Methods
Abstract classes serve as templates
and cannot be instantiated. They may
include abstract methods, which have
no implementation in the base class
and must be overridden in any
derived class.
Usage:
Sealed Classes and Methods
The sealed keyword prevents a class or method from being further inherited
or overridden.
1. Sealed Class: Prevents the class from being used as a
base class.
Usage:
Here:
• Name cannot be null, so assigning null to
it will produce a waming.
Example:
Example:
This is particularly helpful for initializing values that may not yet be
set.
6. NullReferenceException Handling
NullReferenceException is a runtime error that occurs when you
attempt to
access a member of a null object. You can prevent it by:
• using null checks before accessing members.
• using nullable types and the null conditional operator to handle
potential
null values safely.
Example:
7. Null Checking with is and switch Statements
You can use pattern matching with is or switch expressions for null
checking.
Example with is :
Example:
9. Null Forgiving Operator ( ! )
The null-forgiving operator (!) tells the compiler that a nullable
variable will not
be null at runtime, preventing warnings about nullability. Use it with
caution as it
suppresses compiler warnings but does not provide runtime safety.
Example:
This should be used sparingly, typically when you have external logic
ensuring a variable isn't null but the compiler doesn't recognize it.
Summary of Null-Handling Techniques
Here:
Here:
• The myAnimal object is downcast to a Dog
reference, allowing access to Bark().
In this example:
Here:
• Not all .NET types can be inherited (e.g., string, DateTime , and Math are
led).
• Use inheritance when you need to modify behavior or add functionality that
fits naturally within the type's purpose.
Example: Custom List Class
Let's extend the List<T> class to create a LimetedList<T> that
enforces a maximum capacity.
Usage:
Here:
Usage in
LimitedList:
Here:
Usage:
Summary of Extending .NET Types