diff --git a/019_branching_and_looping_structures/019_csharp.md b/019_branching_and_looping_structures/019_csharp.md
index c1c285b..b00d988 100644
--- a/019_branching_and_looping_structures/019_csharp.md
+++ b/019_branching_and_looping_structures/019_csharp.md
@@ -407,3 +407,10 @@ data that filled gaps in the ourAnimals array.
Your ability to implement features of the Contoso Pets application based on a
design specification demonstrates your understanding of the iteration and
selection statements.
+
+---
+
+Project Files
+
+- [Final](./ChallengeProject/Final/Program.cs)
+- [Own](./ChallengeProject/Own/Program.cs)
diff --git a/020_data_types/020_csharp.md b/020_data_types/020_csharp.md
new file mode 100644
index 0000000..9fe7c28
--- /dev/null
+++ b/020_data_types/020_csharp.md
@@ -0,0 +1,645 @@
+# Choose the correct data type in your C# code
+
+## Introduction
+
+The C# programming language relies on data types extensively. Data types
+restrict the kinds of values that can be stored in a given variable, which can
+be helpful when trying to create error free code. As a developer, you
+confidently perform operations on your variables because you know in advance
+that it only stores valid values.
+
+Suppose your job is to build a new application that must retrieve, manipulate,
+and store many different kinds of data, including individual numeric values and
+sequences of numeric and text values. Choosing the right data types is critical
+to the success of your software development efforts. But what are your options,
+and what criteria should you use when faced with several data types that seem
+similar?
+
+In this module, you learn how your application stores and processes data. You
+learn that there are two kinds of data types that correspond with the two ways
+that data is processed. You write code that identifies the maximum and minimum
+values that can be stored in a particular numeric data type. And, you learn the
+criteria to use when choosing between several numeric data types for your
+application.
+
+By the end of this module, you'll be confident when working with different data
+types in C# and able to choose the right data type for your particular application.
+
+### Learning objectives
+
+- Learn the fundamental differences between value types and reference types.
+- Describe the properties of many new numeric data types, including new
+integral types and floating point types.
+- Write code that returns the maximum and minimum values that numeric data
+types can store.
+- Use the new keyword to create new instances of a reference type.
+- Determine which data type you should choose for a given application.
+
+## Discover value types and reference types
+
+With many data types available in C#, choosing the right one to use means that
+you need to understand when you might choose one data type over another.
+
+Before discussing why you might choose one data type over another, you need to
+understand more about data types. You also need to know how data and data types
+work in C# and .NET.
+
+### What is data?
+
+Answering the question "what is data" depends on who you ask, and in what
+context you're asking it.
+
+In software development, data is essentially a value that is stored in the
+computer's memory as a series of bits. A bit is a simple binary switch
+represented as a `0` or `1`, or rather, "off" and "on." A single bit doesn't
+seem useful, however when you combine 8 bits together in a sequence, they form
+a byte. When used in a byte, each bit takes on a meaning in the sequence. In
+fact, you can represent 256 different combinations with just 8 bits if you use
+a binary (base-2) numeral system.
+
+For example, in a binary numeral system, you can represent the number `195` as
+`11000011`. The following table helps you visualize how this works. The first
+row has eight columns that correspond to a position in a byte. Each position
+represents a different numeric value. The second row can store the value of an
+individual bit, either 0 or 1.
+
+
+
+| | | | | | | | |
+| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
+| 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
+| 1 | 1 | 0 | 0 | 0 | 0 | 1 | 1 |
+
+
+
+If you add up the number from each column in the first row that corresponds to
+a `1` in the second row, you get the decimal equivalent to the binary numeral
+system representation. In this case, it would be `128 + 64 + 2 + 1 = 195`.
+
+To work with larger values beyond `255`, your computer stores more bytes
+(commonly 32-bit or 64-bit). If you're working with millions of large numbers
+in a scientific setting, you may need to consider more carefully which data
+types you're using. Your code could require more memory to run.
+
+#### What about textual data?
+
+If a computer only understands `0s` and `1s`, then how does it allow you to work
+with text? Using a system like ASCII (American Standard Code for Information
+Interchange), you can use a single byte to represent upper and lowercase
+letters, numbers, tab, backspace, newline and many mathematical symbols.
+
+For example, if you wanted to store a lower-case letter `a` as a value in my
+application, the computer would only understand the binary form of that value.
+To better understand how a lower-case letter `a` is handled by the computer, I
+need to locate an ASCII table that provides ASCII values and their decimal
+equivalents. You can search for the terms "ASCII lookup decimal" to locate such
+a resource online.
+
+In this case, the lower-case letter `a` is equivalent to the decimal value `97`.
+Then, you would use the same binary numeral system in reverse to find how an
+ASCII letter `a` is stored by the computer.
+
+
+
+
+| | | | | | | | |
+| :-: | :-: | :-: | :-: | :-: | :-: | :-: | :-: |
+| 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
+| 0 | 1 | 1 | 0 | 0 | 0 | 0 | 1 |
+
+
+
+Since `64 + 32 + 1 = 97`, the 8-bit binary ASCII code for `a` is `01100001`.
+
+It's likely that you'll never need to perform these types of conversions on
+your own, but understanding the computer's perspective of data is a
+foundational concept, especially as you're considering data types.
+
+#### What is a data type?
+
+A data type is a way a programming language defines how much memory to save for
+a value. There are many data types in the C# language to be used for many
+different applications and sizes of data.
+
+For most of the applications you build in your career, you'll settle on a small
+subset of all the available data types. However, it's still vital to know
+others exist and why.
+
+#### Value vs. reference types
+
+This module focuses on the two kinds of types in C#: reference types and value
+types.
+
+Variables of reference types store references to their data (objects), that is
+they point to data values stored somewhere else. In comparison, variables of
+value types directly contain their data. As you learn more about C#, new
+details emerge related to the fundamental difference between value and
+reference types.
+
+#### Simple value types
+
+Simple value types are a set of predefined types provided by C# as keywords.
+These keywords are aliases (a nickname) for predefined types defined in the
+.NET Class Library. For example, the C# keyword `int` is an alias of a value
+type defined in the .NET Class Library as `System.Int32`.
+
+Simple value types include many of the data types that you may have used
+already like `char` and `bool`. There are also many integral and floating-point
+value types to represent a wide range of whole and fractional numbers.
+
+### Recap
+
+Values are stored as bits, which are simple on / off switches. Combining enough
+of these switches allows you to store just about any possible value.
+There are two basic categories of data types: value and reference types. The
+difference is in how and where the values are stored by the computer as your
+program executes.
+Simple value types use a keyword alias to represent formal names of types in
+the .NET Library.
+
+---
+
+## Exercise
+
+### Discover integral types
+
+In this exercise, you work with integral types. An integral type is a simple
+value type that represents whole numbers with no fraction (such as `-1`, `0`,
+`1`, `2`, `3`). The most popular in this category is the `int` data type.
+
+There are two subcategories of integral types: **signed** and **unsigned**
+integral types.
+
+A signed type uses its bytes to represent an equal number of positive and
+negative numbers. The following exercise gives you exposure to the signed
+integral types in C#.
+
+#### Prepare your coding environment
+
+You're using this C# console project to create, build, and run code samples
+during this module.
+
+#### Use the MinValue and MaxValue properties for each signed integral type
+
+Program.cs should be empty. If it isn't, select and delete all code lines.
+
+To see the value ranges for the various data types, type the following code
+into the code editor.
+
+```cs
+Console.WriteLine("Signed integral types:");
+
+Console.WriteLine($"sbyte : {sbyte.MinValue} to {sbyte.MaxValue}");
+Console.WriteLine($"short : {short.MinValue} to {short.MaxValue}");
+Console.WriteLine($"int : {int.MinValue} to {int.MaxValue}");
+Console.WriteLine($"long : {long.MinValue} to {long.MaxValue}");
+```
+
+The Program.cs file must be saved before building or running the code.
+
+At the Terminal command prompt, to run your code, type `dotnet run` and then
+press Enter.
+
+You should see the following output:
+
+```txt
+Signed integral types:
+sbyte : -128 to 127
+short : -32768 to 32767
+int : -2147483648 to 2147483647
+long : -9223372036854775808 to 9223372036854775807
+```
+
+For most non-scientific applications, you likely only need to work with int.
+Most of the time, you won't need more than a positive to negative 2.14 billion
+whole numbers.
+
+### Unsigned integral types
+
+An unsigned type uses its bytes to represent only positive numbers. The
+remainder of the exercise introduces the unsigned integral types in C#.
+
+#### Use the MinValue and MaxValue properties for each unsigned integral type
+
+Below the previous code passage, add the following code:
+
+```cs
+Console.WriteLine("");
+Console.WriteLine("Unsigned integral types:");
+
+Console.WriteLine($"byte : {byte.MinValue} to {byte.MaxValue}");
+Console.WriteLine($"ushort : {ushort.MinValue} to {ushort.MaxValue}");
+Console.WriteLine($"uint : {uint.MinValue} to {uint.MaxValue}");
+Console.WriteLine($"ulong : {ulong.MinValue} to {ulong.MaxValue}");
+```
+
+Save your code file, and then run your code.
+
+You should see the following output:
+
+```txt
+Signed integral types:
+sbyte : -128 to 127
+short : -32768 to 32767
+int : -2147483648 to 2147483647
+long : -9223372036854775808 to 9223372036854775807
+
+Unsigned integral types:
+byte : 0 to 255
+ushort : 0 to 65535
+uint : 0 to 4294967295
+ulong : 0 to 18446744073709551615
+```
+
+While a given data type can be used for many cases, given the fact that the
+`byte` data type can represent a value from 0 to 255, it's obvious that this is
+intended to hold a value that represents a byte of data. Data stored in files
+or data transferred across the internet is often in a binary format. When
+working with data from these external sources, you need to receive data as an
+array of bytes, then convert them into strings. Many of the methods in the .NET
+Class Library that deal with encoding and decoding data requires you handle byte
+arrays.
+
+### Recap
+
+- An integral type is a simple value data type that can hold whole numbers.
+- There are signed and unsigned numeric data types. Signed integral types use 1
+bit to store whether the value is positive or negative.
+- You can use the `MaxValue` and `MinValue` properties of numeric data types to
+evaluate whether a number can fit in a given data type.
+
+---
+
+## Exercise
+
+### Discover floating-point types
+
+In this exercise, you work with floating-point data types to learn about the
+nuanced differences between each data type.
+
+A floating point is a simple value type that represents numbers to the right of
+the decimal place. Unlike integral numbers, there are other considerations
+beyond the maximum and minimum values you can store in a given floating-point
+type.
+
+#### Evaluate floating-point types
+
+First, you must consider the digits of precision each type allows. Precision is
+the number of value places stored after the decimal point.
+
+Second, you must consider the manner in which the values are stored and the
+impact on the accuracy of the value. For example, `float` and `double` values are
+stored internally in a binary (base 2) format, while `decimal` is stored in a
+decimal (base 10) format. Why does this matter?
+
+Performing math on binary floating-point values can produce results that may
+surprise you if you're used to decimal (base 10) math. Often, binary
+floating-point math is an approximation of the real value. Therefore, `float` and
+`double` are useful because large numbers can be stored using a small memory
+footprint. However, `float` and `double` should only be used when an
+approximation is useful. For example, being a few thousandths off when
+calculating the splatter of a snowball in a video game is close enough.
+
+When you need more a more precise answer, you should use `decimal`. Each value
+of type `decimal` has a relatively large memory footprint, however performing
+math operations gives you a more precise result. So, you should use decimal
+when working with financial data or any scenario where you need an accurate
+result from a calculation.
+
+#### Use the MinValue and MaxValue properties for each signed float type
+
+- Delete or use the line comment operator `//` to comment out all of the code from
+the previous exercises.
+
+- To see the value ranges for the various data types, update your code in the
+editor as follows:
+
+```cs
+Console.WriteLine("");
+Console.WriteLine("Floating point types:");
+Console.WriteLine($"float : {float.MinValue} to {float.MaxValue} (with ~6-9 digits of precision)");
+Console.WriteLine($"double : {double.MinValue} to {double.MaxValue} (with ~15-17 digits of precision)");
+Console.WriteLine($"decimal: {decimal.MinValue} to {decimal.MaxValue} (with 28-29 digits of precision)");
+```
+
+The Program.cs file must be saved before building or running the code.
+
+At the Terminal command prompt, to run your code, type `dotnet run` and then
+press Enter.
+
+You should see the following output:
+
+```txt
+Floating point types:
+float : -3.402823E+38 to 3.402823E+38 (with ~6-9 digits of precision)
+double : -1.79769313486232E+308 to 1.79769313486232E+308 (with ~15-17 digits of precision)
+decimal: -79228162514264337593543950335 to 79228162514264337593543950335 (with 28-29 digits of precision)
+```
+
+As you can see, `float` and `double` use a different notation than is used by
+`decimal` to represent its largest and smallest possible values. But what does
+this notation mean?
+
+#### Deciphering large floating-point values
+
+Because floating-point types can hold large numbers with precision, their
+values can be represented using "E notation", which is a form of scientific
+notation that means "times 10 raised to the power of." So, a value like `5E+2`
+would be the value 500 because it's the equivalent of `5 x 10^2`, or `5 x 10²`.
+
+### Recap
+
+- A floating-point type is a simple value data type that can hold fractional
+numbers.
+- Choosing the right floating-point type for your application requires you to
+consider more than just the maximum and minimum values that it can hold. You
+must also consider how many values can be preserved after the decimal, how the
+numbers are stored, and how their internal storage affects the outcome of math
+operations.
+- Floating-point values can sometimes be represented using "E notation" when
+the numbers grow especially large.
+- There's a fundamental difference in how the compiler and runtime handle
+decimal as opposed to float or double, especially when determining how much
+accuracy is necessary from math operations.
+
+---
+
+## Exercise - Discover reference types
+
+Reference types include arrays, classes, and strings. Reference types are
+treated differently from value types regarding the way values are stored when
+the application is executing.
+
+In this exercise, you learn how reference types are different from value types,
+and how to use the `new` operator to associate a variable with a value in the
+computer's memory.
+
+### How reference types are different from value types
+
+A value type variable stores its values directly in an area of storage called
+the stack. The stack is memory allocated to the code that is currently running
+on the CPU (also known as the stack frame, or activation frame). When the stack
+frame has finished executing, the values in the stack are removed.
+
+A reference type variable stores its values in a separate memory region called
+the heap. The heap is a memory area that is shared across many applications
+running on the operating system at the same time. The .NET Runtime communicates
+with the operating system to determine what memory addresses are available, and
+requests an address where it can store the value. The .NET Runtime stores the
+value, and then returns the memory address to the variable. When your code uses
+the variable, the .NET Runtime seamlessly looks up the address stored in the
+variable, and retrieves the value that's stored there.
+
+You'll next write some code that illustrates these ideas more clearly.
+
+### Define a reference type variable
+
+Delete or use the line comment operator `//` to comment out all of the code
+from the previous exercises.
+
+Update your code in the editor as follows:
+
+```cs
+int[] data;
+```
+
+The previous code defines a variable that can hold a value of type int array.
+
+At this point, `data` is merely a variable that could hold a reference, or
+rather, a memory address of a value in the heap. Because it's not pointing to a
+memory address, it's called a null reference.
+
+Create an instance of `int` array using the `new` keyword
+
+Update your code in the editor to create and assign a new instance of `int`
+array, using the following code:
+
+
+```cs
+int[] data;
+data = new int[3];
+```
+
+The `new` keyword informs .NET Runtime to create an instance of `int` array,
+and then coordinate with the operating system to store the array sized for
+three int values in memory. The .NET Runtime complies, and returns a memory
+address of the new `int` array. Finally, the memory address is stored in the
+variable data. The `int` array's elements default to the value `0`, because that
+is the default value of an `int`.
+
+Modify the code example to perform both operations in a single line of code
+
+The two lines of code in the previous step are typically shortened to a single
+line of code to both declare the variable, and create a new instance of the
+`int` array. Modify the code from step 3 to the following.
+
+```cs
+int[] data = new int[3];
+```
+
+While there's no output to observe, hopefully this exercise added clarity to
+how the C# syntax relates to the steps of the process for working with
+reference types.
+
+#### What's different about the C# string data type?
+
+The `string` data type is also a reference type. You might be wondering why a
+`new` operator wasn't used when declaring a string. This is purely a convenience
+afforded by the designers of C#. Because the `string` data type is used so
+frequently, you can use this format:
+
+```cs
+string shortenedString = "Hello World!";
+Console.WriteLine(shortenedString);
+```
+
+Behind the scenes, however, a new instance of `System.String` is created and
+initialized to "Hello World!".
+
+#### Practical concerns using value and reference types
+
+1. **Value Type (int)**: In this example, `val_A` and `val_B` are integer value types.
+
+ ```cs
+ int val_A = 2;
+ int val_B = val_A;
+ val_B = 5;
+
+ Console.WriteLine("--Value Types--");
+ Console.WriteLine($"val_A: {val_A}");
+ Console.WriteLine($"val_B: {val_B}");
+ ```
+
+ You should see the following output:
+
+ ```txt
+ --Value Types--
+ val_A: 2
+ val_B: 5
+ ```
+
+ When `val_B` = `val_A` is executed, the value of `val_A` is copied and stored in
+ `val_B`. So, when `val_B` is changed, `val_A` remains unaffected.
+
+2. **Reference Type (array)**: In this example, `ref_A` and `ref_B` are array
+reference types.
+
+ ```cs
+ int[] ref_A= new int[1];
+ ref_A[0] = 2;
+ int[] ref_B = ref_A;
+ ref_B[0] = 5;
+
+ Console.WriteLine("--Reference Types--");
+ Console.WriteLine($"ref_A[0]: {ref_A[0]}");
+ Console.WriteLine($"ref_B[0]: {ref_B[0]}");
+ ```
+
+ You should see the following output:
+
+ ```txt
+ --Reference Types--
+ ref_A[0]: 5
+ ref_B[0]: 5
+ ```
+
+ When `ref_B` = `ref_A` is executed, `ref_B` points to the same memory
+ location as `ref_A`. So, when `ref_B[0]` is changed, `ref_A[0]` also changes
+ because they both point to the same memory location. This is a key difference
+ between value types and reference types.
+
+### Recap
+
+- Value types can hold smaller values and are stored in the stack. Reference
+types can hold large values, and a new instance of a reference type is created
+using the `new` operator. Reference type variables hold a reference (the memory
+address) to the actual value stored in the heap.
+- Reference types include arrays, strings, and classes.
+
+---
+
+## Choose the right data type
+
+You've been introduced to the difference between value types and reference type
+s, as well as integral and floating point types.
+
+Suppose your job is to build a new application that retrieves, manipulates, and
+stores different types of data. Which data types do you use?
+
+In some cases, it is an easy choice. For example, when you need to work with
+text, then you default to using the `string` data type unless you need to
+perform a significant amount of concatenation.
+
+But what about working with numeric data? There are 11 different options. How
+do you choose the right data type?
+
+### Choose the right data type
+
+With so many data types to choose from, what criteria should you use to choose
+the right data type for the particular situation?
+
+When evaluating your options, you must weigh several important considerations.
+Often there's no one single correct answer, but some answers are more correct
+than others.
+
+#### Choose the data type that meets the boundary value range requirements of your application
+
+Your choice of a data type can help to set the boundaries for the size of the
+data you might store in that particular variable. For example, if you know a
+particular variable should only store a number between 1 and 10,000 otherwise
+it's outside of the boundaries of what would be expected, you would likely
+avoid `byte` and `sbyte` since their ranges are too low.
+
+Furthermore, you would likely not need `int`, `long`, `uint`, and `ulong`
+because they can store more data than is necessary. Likewise, you would
+probably skip `float`, `double`, and `decimal` if you didn't need fractional
+values. You might narrow it down to `short` and `ushort`, of which both may be
+viable. If you're confident that a negative value would have no meaning in your
+application, you might choose `ushort` (positive unsigned integer, 0 to 65,535).
+Now, any value assigned to a variable of type `ushort` outside of the boundary
+of 0 to 65535 would throw an exception, thereby subtly helping you enforce a
+degree of sanity checking in your application.
+
+#### Start with choosing the data type to fit the data (not to optimize performance)
+
+You may be tempted to choose the data type that uses the fewest bits to store
+data thinking it improves your application's performance. However, some of the
+best advice related to application performance (that is, how fast your
+application runs) is to not "prematurely optimize". You should resist the
+temptation to guess at the parts of your code, including the selection of data
+types that may impact your application's performance.
+
+Many assume that because a given data type stores less information it must use
+less of the computer's processor and memory than a data type that stores more
+information. Instead, you should choose the right fit for your data, then later
+you can empirically measure the performance of your application using special
+software that provides factual insights to the parts of your application that
+negatively impact performance.
+
+#### Choose data types based on the input and output data types of library functions used
+
+Suppose you want to work with a span of years between two dates. Since the
+application is a business application, you might determine that you only need a
+range from about 1960 to 2200. You might think to try to work with byte since
+it can represent numbers between 0 and 255.
+
+However, when you look at the built-in methods on the `System.TimeSpan` and
+`System.DateTime` classes, you realize they mostly accept values of type
+`double` and `int`. If you choose `sbyte`, you'll constantly be casting back
+and forth between `sbyte` and `double` or `int`. In this case, it might make
+more sense to choose `int` if you don't need subsecond precision, and `double`
+if you do need subsecond precision.
+
+#### Choose data types based on impact to other systems
+
+Sometimes, you must consider how the information will be consumed by other
+applications or other systems like a database. For example, SQL Server's type
+system is different from C#'s type system. As a result, some mapping between
+the two must happen before you can save data into that database.
+
+If your application's purpose is to interface with a database, then you would
+likely need to consider how the data is stored and how much data is stored. The
+choice of a larger data type might impact the amount (and cost) of the physical
+storage required to store all the data your application will generate.
+
+#### When in doubt, stick with the basics
+
+While you've looked at several considerations, as you're getting started, for
+simplicity's sake you should prefer a subset of basic data types, including:
+
+- `int` for most whole numbers
+- `decimal` for numbers representing money
+- `bool` for true or false values
+- `string` for alphanumeric value
+
+#### Choose specialty complex types for special situations
+
+Don't reinvent data types if one or more data type already exists for a given
+purpose. The following examples identify where a specific .NET data types can
+be useful:
+
+- `byte`: working with encoded data that comes from other computer systems or
+using different character sets.
+- `double`: working with geometric or scientific purposes. double is used
+frequently when building games involving motion.
+- `System.DateTime` for a specific date and time value.
+- `System.TimeSpan` for a span of years / months / days / hours / minutes /
+seconds / milliseconds.
+
+### Recap
+
+There are considerations when choosing data types for your code, and often more
+than one option. Think through your choices, and unless you have a good reason,
+try to stick with the basic types like `int`, `decimal`, `string`, and `bool`.
+
+## Summary
+
+Choosing the right data type for your application is a vital programming skill.
+Your goal was to understand the differences between each data type to make an
+informed decision on the data types in your code.
+
+You started building a mental model of how data is stored as your application
+executes. You have experience working with new integral and floating point data
+types. You have criteria you can use when deciding which data types to employ
+in your code. Finally, you understand why you need to use the `new` keyword when
+creating instances of reference types.
diff --git a/020_data_types/test_app/Program.cs b/020_data_types/test_app/Program.cs
new file mode 100644
index 0000000..bda0684
--- /dev/null
+++ b/020_data_types/test_app/Program.cs
@@ -0,0 +1,36 @@
+Console.WriteLine("-------------------------------------------");
+Console.WriteLine("Signed integral types:");
+Console.WriteLine($"sbyte : {sbyte.MinValue} to {sbyte.MaxValue}");
+Console.WriteLine($"short : {short.MinValue} to {short.MaxValue}");
+Console.WriteLine($"int : {int.MinValue} to {int.MaxValue}");
+Console.WriteLine($"long : {long.MinValue} to {long.MaxValue}");
+Console.WriteLine("-------------------------------------------");
+Console.WriteLine("Unsigned integral types:");
+Console.WriteLine($"byte : {byte.MinValue} to {byte.MaxValue}");
+Console.WriteLine($"ushort : {ushort.MinValue} to {ushort.MaxValue}");
+Console.WriteLine($"uint : {uint.MinValue} to {uint.MaxValue}");
+Console.WriteLine($"ulong : {ulong.MinValue} to {ulong.MaxValue}");
+
+Console.WriteLine("-------------------------------------------");
+Console.WriteLine("Floating point types:");
+Console.WriteLine($"float : {float.MinValue} to {float.MaxValue} (with ~6-9 digits of precision)");
+Console.WriteLine($"double : {double.MinValue} to {double.MaxValue} (with ~15-17 digits of precision)");
+Console.WriteLine($"decimal: {decimal.MinValue} to {decimal.MaxValue} (with 28-29 digits of precision)");
+Console.WriteLine("-------------------------------------------");
+int val_A = 2;
+int val_B = val_A;
+val_B = 5;
+
+Console.WriteLine("--Value Types--");
+Console.WriteLine($"val_A: {val_A}");
+Console.WriteLine($"val_B: {val_B}");
+
+int[] ref_A= new int[1];
+ref_A[0] = 2;
+int[] ref_B = ref_A;
+ref_B[0] = 5;
+
+Console.WriteLine("--Reference Types--");
+Console.WriteLine($"ref_A[0]: {ref_A[0]}");
+Console.WriteLine($"ref_B[0]: {ref_B[0]}");
+Console.WriteLine("-------------------------------------------");
diff --git a/020_data_types/test_app/test_app.csproj b/020_data_types/test_app/test_app.csproj
new file mode 100644
index 0000000..2150e37
--- /dev/null
+++ b/020_data_types/test_app/test_app.csproj
@@ -0,0 +1,10 @@
+
+
+
+ Exe
+ net8.0
+ enable
+ enable
+
+
+
diff --git a/README.md b/README.md
index d62463c..dd62589 100644
--- a/README.md
+++ b/README.md
@@ -24,3 +24,4 @@ Following
- [Looping logic using the do-while and while](./017_Looping_logic_using_do-while_and_while/017_csharp.md)
- [Conditional branching and looping](./018_Conditional_branching_and_looping/018_csharp.md)
- [Branching and looping structures](./019_branching_and_looping_structures/019_csharp.md)
+- [Choose the correct data type](/020_data_types/020_csharp.md)