diff --git a/docfx.json b/docfx.json index d2bbde73ae74e..23b61fa08778a 100644 --- a/docfx.json +++ b/docfx.json @@ -463,7 +463,7 @@ "_csharplang/proposals/csharp-9.0/*.md": "07/29/2020", "_csharplang/proposals/csharp-10.0/*.md": "08/07/2021", "_csharplang/proposals/csharp-11.0/*.md": "09/30/2022", - "_csharplang/proposals/*.md": "04/03/2023", + "_csharplang/proposals/*.md": "07/06/2023", "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "11/08/2022", "_vblang/spec/*.md": "07/21/2017" }, @@ -665,6 +665,8 @@ "_csharplang/proposals/primary-constructors.md": "Primary constructors", "_csharplang/proposals/using-alias-types.md": "Alias any type", "_csharplang/proposals/lambda-method-group-defaults.md": "Optional and parameter array parameters for lambdas and method groups", + "_csharplang/proposals/inline-arrays.md": "Inline arrays, or fixed sized buffers", + "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "C# compiler breaking changes since C# 10", "_vblang/spec/introduction.md": "Introduction", @@ -774,8 +776,9 @@ "_csharplang/proposals/primary-constructors.md": "Primary constructors put the parameters of one constructor in scope for the whole class or struct to be used for initialization or directly as object state. The trade-off is that any other constructors must call through the primary constructor.", "_csharplang/proposals/using-alias-types.md": "Using directives can alias any type, not just named types. You can create aliases for tuple types, generics and more.", - "_csharplang/proposals/lambda-method-group-defaults.md": "Lambda expressions can now declare default parameters and params arrays parameters.", - + "_csharplang/proposals/lambda-method-group-defaults.md": "Optional and parameter array parameters for lambdas and method groups", + "_csharplang/proposals/inline-arrays.md": "Inline arrays provide a general-purpose and safe mechanism for declaring inline arrays within C# classes, structs, and interfaces.", + "_roslyn/docs/compilers/CSharp/Compiler Breaking Changes - DotNet 7.md": "Learn about any breaking changes since the initial release of C# 10", "_vblang/spec/introduction.md": "This chapter provides and introduction to the Visual Basic language.", "_vblang/spec/lexical-grammar.md": "This chapter defines the lexical grammar for Visual Basic.", diff --git a/docs/core/tools/dotnet-install-script.md b/docs/core/tools/dotnet-install-script.md index 0efc757e52742..cc597685ef30e 100644 --- a/docs/core/tools/dotnet-install-script.md +++ b/docs/core/tools/dotnet-install-script.md @@ -1,7 +1,7 @@ --- title: dotnet-install scripts description: Learn about the dotnet-install scripts to install the .NET SDK and the shared runtime. -ms.date: 11/08/2021 +ms.date: 07/10/2023 --- # dotnet-install scripts reference @@ -45,8 +45,8 @@ The bash script also reads PowerShell switches, so you can use PowerShell switch The `dotnet-install` scripts perform a non-admin installation of the .NET SDK, which includes the .NET CLI and the shared runtime. There are two scripts: -* A PowerShell script that works on Windows. -* A bash script that works on Linux/macOS. +* A PowerShell script that works on Windows. For installation instructions, see [Install on Windows](../install/windows.md#install-with-powershell-automation). +* A bash script that works on Linux/macOS. For installation instructions, see [Install on Linux](../install/linux-scripted-manual.md#scripted-install) and [Install on macOS](../install/macos.md#install-with-bash-automation). > [!NOTE] > .NET collects telemetry data. To learn more and how to opt out, see [.NET SDK telemetry](telemetry.md). @@ -80,6 +80,9 @@ By default, the installation scripts download the SDK and install it. If you wis By default, the script adds the install location to the $PATH for the current session. Override this default behavior by specifying the `-NoPath|--no-path` argument. The script doesn't set the `DOTNET_ROOT` environment variable. +> [!IMPORTANT] +> The script doesn't add the install location to the user's `PATH` environment variable, you must manually add it. + Before running the script, install the required [dependencies](../install/windows.md#dependencies). You can install a specific version using the `-Version|--version` argument. The version must be specified as a three-part version number, such as `2.1.0`. If the version isn't specified, the script installs the `latest` version. diff --git a/docs/csharp/fundamentals/tutorials/classes.md b/docs/csharp/fundamentals/tutorials/classes.md index 18e7944b0f7de..1489f5955e164 100644 --- a/docs/csharp/fundamentals/tutorials/classes.md +++ b/docs/csharp/fundamentals/tutorials/classes.md @@ -101,13 +101,13 @@ Did you notice that the account number is blank? It's time to fix that. The acco Add a member declaration to the `BankAccount` class. Place the following line of code after the opening brace `{` at the beginning of the `BankAccount` class: ```csharp -private static int accountNumberSeed = 1234567890; +private static int s_accountNumberSeed = 1234567890; ``` -The `accountNumberSeed` is a data member. It's `private`, which means it can only be accessed by code inside the `BankAccount` class. It's a way of separating the public responsibilities (like having an account number) from the private implementation (how account numbers are generated). It's also `static`, which means it's shared by all of the `BankAccount` objects. The value of a non-static variable is unique to each instance of the `BankAccount` object. Add the following two lines to the constructor to assign the account number. Place them after the line that says `this.Balance = initialBalance`: +The `accountNumberSeed` is a data member. It's `private`, which means it can only be accessed by code inside the `BankAccount` class. It's a way of separating the public responsibilities (like having an account number) from the private implementation (how account numbers are generated). It's also `static`, which means it's shared by all of the `BankAccount` objects. The value of a non-static variable is unique to each instance of the `BankAccount` object. The `accountNumberSeed` is a `private static` field and thus has the `s_` prefix as per C# naming conventions. The `s` denoting `static` and `_` denoting `private` field. Add the following two lines to the constructor to assign the account number. Place them after the line that says `this.Balance = initialBalance`: ```csharp -this.Number = accountNumberSeed.ToString(); +this.Number = s_accountNumberSeed.ToString(); accountNumberSeed++; ``` @@ -133,7 +133,7 @@ This example shows an important aspect of ***properties***. You're now computing Next, implement the `MakeDeposit` and `MakeWithdrawal` methods. These methods will enforce the final two rules: the initial balance must be positive, and any withdrawal must not create a negative balance. -These rules introduce the concept of ***exceptions***. The standard way of indicating that a method can't complete its work successfully is to throw an exception. The type of exception and the message associated with it describe the error. Here, the `MakeDeposit` method throws an exception if the amount of the deposit isn't greater than 0. The `MakeWithdrawal` method throws an exception if the withdrawal amount isn't greater than 0, or if applying the withdrawal results in a negative balance. Add the following code after the declaration of the `allTransactions` list: +These rules introduce the concept of ***exceptions***. The standard way of indicating that a method can't complete its work successfully is to throw an exception. The type of exception and the message associated with it describe the error. Here, the `MakeDeposit` method throws an exception if the amount of the deposit isn't greater than 0. The `MakeWithdrawal` method throws an exception if the withdrawal amount isn't greater than 0, or if applying the withdrawal results in a negative balance. Add the following code after the declaration of the `_allTransactions` list: :::code language="csharp" source="./snippets/introduction-to-classes/BankAccount.cs" id="DepositAndWithdrawal"::: diff --git a/docs/csharp/fundamentals/tutorials/oop.md b/docs/csharp/fundamentals/tutorials/oop.md index 531b95eeaf221..49770e338846b 100644 --- a/docs/csharp/fundamentals/tutorials/oop.md +++ b/docs/csharp/fundamentals/tutorials/oop.md @@ -130,7 +130,7 @@ This implementation calls `MakeDeposit` only if the initial balance is greater t Now that the `BankAccount` class has a read-only field for the minimum balance, the final change is to change the hard code `0` to `minimumBalance` in the `MakeWithdrawal` method: ```csharp -if (Balance - amount < minimumBalance) +if (Balance - amount < _minimumBalance) ``` After extending the `BankAccount` class, you can modify the `LineOfCreditAccount` constructor to call the new base constructor, as shown in the following code: @@ -157,7 +157,7 @@ public void MakeWithdrawal(decimal amount, DateTime date, string note) throw new InvalidOperationException("Not sufficient funds for this withdrawal"); } var withdrawal = new Transaction(-amount, date, note); - allTransactions.Add(withdrawal); + _allTransactions.Add(withdrawal); } ``` diff --git a/docs/csharp/fundamentals/tutorials/snippets/introduction-to-classes/BankAccount.cs b/docs/csharp/fundamentals/tutorials/snippets/introduction-to-classes/BankAccount.cs index eacd7f7a6efae..99f6a789249f4 100644 --- a/docs/csharp/fundamentals/tutorials/snippets/introduction-to-classes/BankAccount.cs +++ b/docs/csharp/fundamentals/tutorials/snippets/introduction-to-classes/BankAccount.cs @@ -13,7 +13,7 @@ public decimal Balance get { decimal balance = 0; - foreach (var item in allTransactions) + foreach (var item in _allTransactions) { balance += item.Amount; } @@ -23,12 +23,12 @@ public decimal Balance } #endregion - private static int accountNumberSeed = 1234567890; + private static int s_accountNumberSeed = 1234567890; #region Constructor public BankAccount(string name, decimal initialBalance) { - Number = accountNumberSeed.ToString(); - accountNumberSeed++; + Number = s_accountNumberSeed.ToString(); + s_accountNumberSeed++; Owner = name; MakeDeposit(initialBalance, DateTime.Now, "Initial balance"); @@ -36,7 +36,7 @@ public BankAccount(string name, decimal initialBalance) #endregion #region TransactionDeclaration - private List allTransactions = new List(); + private List _allTransactions = new List(); #endregion #region DepositAndWithdrawal @@ -47,7 +47,7 @@ public void MakeDeposit(decimal amount, DateTime date, string note) throw new ArgumentOutOfRangeException(nameof(amount), "Amount of deposit must be positive"); } var deposit = new Transaction(amount, date, note); - allTransactions.Add(deposit); + _allTransactions.Add(deposit); } public void MakeWithdrawal(decimal amount, DateTime date, string note) @@ -61,7 +61,7 @@ public void MakeWithdrawal(decimal amount, DateTime date, string note) throw new InvalidOperationException("Not sufficient funds for this withdrawal"); } var withdrawal = new Transaction(-amount, date, note); - allTransactions.Add(withdrawal); + _allTransactions.Add(withdrawal); } #endregion @@ -72,7 +72,7 @@ public string GetAccountHistory() decimal balance = 0; report.AppendLine("Date\t\tAmount\tBalance\tNote"); - foreach (var item in allTransactions) + foreach (var item in _allTransactions) { balance += item.Amount; report.AppendLine($"{item.Date.ToShortDateString()}\t{item.Amount}\t{balance}\t{item.Notes}"); diff --git a/docs/csharp/fundamentals/types/generics.md b/docs/csharp/fundamentals/types/generics.md index 348f60041c3a2..20efa297819be 100644 --- a/docs/csharp/fundamentals/types/generics.md +++ b/docs/csharp/fundamentals/types/generics.md @@ -30,6 +30,9 @@ The following code example shows how client code uses the generic `GenericList [!NOTE] +> Following examples applies not only to `class` types, but also `interface` and `struct` types + ## Generics overview - Use generic types to maximize code reuse, type safety, and performance. diff --git a/docs/csharp/language-reference/builtin-types/snippets/shared/StructType.cs b/docs/csharp/language-reference/builtin-types/snippets/shared/StructType.cs index 099b747f8c61c..03b52f414faeb 100644 --- a/docs/csharp/language-reference/builtin-types/snippets/shared/StructType.cs +++ b/docs/csharp/language-reference/builtin-types/snippets/shared/StructType.cs @@ -259,4 +259,15 @@ public static void Main() // } } + + namespace InlineArrays + { + // + [System.Runtime.CompilerServices.InlineArray(10)] + public struct CharBuffer + { + private char _firstElement; + } + // + } } diff --git a/docs/csharp/language-reference/builtin-types/struct.md b/docs/csharp/language-reference/builtin-types/struct.md index 9bd63005dcc2f..1ef9d0acd8d09 100644 --- a/docs/csharp/language-reference/builtin-types/struct.md +++ b/docs/csharp/language-reference/builtin-types/struct.md @@ -43,7 +43,7 @@ The following code defines a `readonly` struct with init-only property setters, You can also use the `readonly` modifier to declare that an instance member doesn't modify the state of a struct. If you can't declare the whole structure type as `readonly`, use the `readonly` modifier to mark the instance members that don't modify the state of the struct. -Within a `readonly` instance member, you can't assign to structure's instance fields. However, a `readonly` member can call a non-`readonly` member. In that case the compiler creates a copy of the structure instance and calls the non-`readonly` member on that copy. As a result, the original structure instance isn't modified. +Within a `readonly` instance member, you can't assign to structure's instance fields. However, a `readonly` member can call a non-`readonly` member. In that case, the compiler creates a copy of the structure instance and calls the non-`readonly` member on that copy. As a result, the original structure instance isn't modified. Typically, you apply the `readonly` modifier to the following kinds of instance members: @@ -82,6 +82,28 @@ Beginning with C# 10, you can use the [`with` expression](../operators/with-expr Beginning with C# 10, you can define record structure types. Record types provide built-in functionality for encapsulating data. You can define both `record struct` and `readonly record struct` types. A record struct can't be a [`ref struct`](ref-struct.md). For more information and examples, see [Records](record.md). +## Inline arrays + +Beginning with C# 12, you can declare *inline arrays* as a `struct` type: + +:::code language="csharp" source="snippets/shared/StructType.cs" id="DeclareInlineArray"::: + +An inline array is a structure that contains a contiguous block of N elements of the same type. It's a safe-code equivalent of the [fixed buffer](../unsafe-code.md#fixed-size-buffers) declaration available only in unsafe code. An inline array is a `struct` with the following characteristics: + +- It contains a single field. +- The struct doesn't specify an explicit layout. + +In addition, the compiler validates the attribute: + +- The length must be greater than zero (`> 0`). +- The target type must be a struct. + +In most cases, an inline array can be accessed like an array, both to read and write values. In addition, you can use the [range](../operators/member-access-operators.md#range-operator-) and [index](../operators/member-access-operators.md#indexer-access) operators. + +There are minimal restrictions on the type of the single field. It can't be a pointer type, but it can be any reference type, or any value type. You can use inline arrays with almost any C# data structure. + +Inline arrays are an advanced language feature. They're intended for high-performance scenarios where an inline, contiguous block of elements is faster than other alternative data structures. You can learn more about inline arrays from the [feature speclet](~/_csharplang/proposals/inline-arrays.md) + ## Struct initialization and default values A variable of a `struct` type directly contains the data for that `struct`. That creates a distinction between an uninitialized `struct`, which has its default value and an initialized `struct`, which stores values set by constructing it. For example consider the following code: @@ -108,7 +130,7 @@ Beginning with C# 11, if you don't initialize all fields in a struct, the compil Every `struct` has a `public` parameterless constructor. If you write a parameterless constructor, it must be public. If a struct declares any field initializers, it must explicitly declare a constructor. That constructor need not be parameterless. If a struct declares a field initializer but no constructors, the compiler reports an error. Any explicitly declared constructor (with parameters, or parameterless) executes all field initializers for that struct. All fields without a field initializer or an assignment in a constructor are set to the [default value](default-values.md). For more information, see the [Parameterless struct constructors](~/_csharplang/proposals/csharp-10.0/parameterless-struct-constructors.md) feature proposal note. -Beginning with C# 12, `struct` types can define a [primary constructor](../../programming-guide/classes-and-structs/instance-constructors.md#primary-constructors) as part of its declaration. This provides a concise syntax for constructor parameters that can be used throughout the `struct` body, in any member declaration for that struct. +Beginning with C# 12, `struct` types can define a [primary constructor](../../programming-guide/classes-and-structs/instance-constructors.md#primary-constructors) as part of its declaration. Primary constructors provides a concise syntax for constructor parameters that can be used throughout the `struct` body, in any member declaration for that struct. If all instance fields of a structure type are accessible, you can also instantiate it without the `new` operator. In that case you must initialize all instance fields before the first use of the instance. The following example shows how to do that: diff --git a/docs/csharp/language-reference/compiler-options/errors-warnings.md b/docs/csharp/language-reference/compiler-options/errors-warnings.md index 82cdf53166193..d2dcf7101edc5 100644 --- a/docs/csharp/language-reference/compiler-options/errors-warnings.md +++ b/docs/csharp/language-reference/compiler-options/errors-warnings.md @@ -44,7 +44,7 @@ The element value is the warning level you want displayed for the compilation: L | 1 | Displays severe warning messages. | | 2 | Displays level 1 warnings plus certain, less-severe warnings, such as warnings about hiding class members. | | 3 | Displays level 2 warnings plus certain, less-severe warnings, such as warnings about expressions that always evaluate to `true` or `false`. | -| 4 (the default)|Displays all level 3 warnings plus informational warnings. | +| 4 (default) | Displays all level 3 warnings plus informational warnings. | > [!WARNING] > The compiler command line accepts values greater than 4 to enable [warning wave warnings](../compiler-messages/warning-waves.md). However, the .NET SDK sets the *WarningLevel* to match the *AnalysisLevel* in your project file. @@ -53,6 +53,12 @@ To get information about an error or warning, you can look up the error code in ## Analysis level +The **AnalysisLevel** option specifies additional [warning waves](../compiler-messages/warning-waves.md) and analyzers to enable. Warning wave warnings are additional checks that improve your code, or ensure it will be compatible with upcoming releases. Analyzers provide lint-like capability to improve your code. + +```xml +preview +``` + | Analysis level | Meaning | |------------------|---------| | 5 | Displays all optional [warning wave 5 warnings](../compiler-messages/warning-waves.md#cs7023---a-static-type-is-used-in-an-is-or-as-expression). | diff --git a/docs/csharp/properties.md b/docs/csharp/properties.md index 5700bfbef7b08..ec87925306011 100644 --- a/docs/csharp/properties.md +++ b/docs/csharp/properties.md @@ -92,7 +92,7 @@ The preceding example allows a caller to create a `Person` using the default con :::code language="csharp" source="./snippets/properties/Person.cs" id="Snippet9.2"::: -The preceding code makes two addition to the `Person` class. First, the `FirstName` property declaration includes the `required` modifier. That means any code that creates a new `Person` must set this property. Second, the constructor that takes a `firstName` parameter has the attribute. This attribute informs the compiler that this constructor sets *all* `required` members. +The preceding code makes two additions to the `Person` class. First, the `FirstName` property declaration includes the `required` modifier. That means any code that creates a new `Person` must set this property. Second, the constructor that takes a `firstName` parameter has the attribute. This attribute informs the compiler that this constructor sets *all* `required` members. > [!IMPORTANT] > Don't confuse `required` with *non-nullable*. It's valid to set a `required` property to `null` or `default`. If the type is non-nullable, such as `string` in these examples, the compiler issues a warning. diff --git a/docs/csharp/toc.yml b/docs/csharp/toc.yml index b82b0b67ba064..b4de694bce8fd 100644 --- a/docs/csharp/toc.yml +++ b/docs/csharp/toc.yml @@ -1426,3 +1426,5 @@ items: href: ../../_csharplang/proposals/using-alias-types.md - name: Optional Lambda expression parameters href: ../../_csharplang/proposals/lambda-method-group-defaults.md + - name: Inline arrays + href: ../../_csharplang/proposals/inline-arrays.md diff --git a/docs/csharp/whats-new/csharp-12.md b/docs/csharp/whats-new/csharp-12.md index bb1d3fda3cfdb..13e186f805ebf 100644 --- a/docs/csharp/whats-new/csharp-12.md +++ b/docs/csharp/whats-new/csharp-12.md @@ -10,6 +10,7 @@ Some C# 12 features have been introduced in previews. You can try these features - [Primary constructors](#primary-constructors) - Introduced in Visual Studio 17.6 preview 2. - [Optional parameters in lambda expressions](#default-lambda-parameters) - Introduced in Visual Studio 17.5 preview 2. - [Alias any type](#alias-any-type) - Introduced in Visual Studio 17.6 preview 3. +- [Inline arrays](#inline-arrays) - Introduced in Visual Studio 17.7 preview 3. - [Interceptors](#interceptors) - *Preview feature* Introduced in Visual Studio 17.7, preview 3. ## Primary constructors @@ -28,7 +29,38 @@ You can learn more about default parameters on lambda expressions in the article ## Alias any type -You can use the `using` alias directive to alias any type, not just named types. That means you can create semantic aliases for tuple types, array types, pointer types, or other unsafe types. For more information, see the [feature specification](~/_csharplang/proposals/using-alias-types.md) +You can use the `using` alias directive to alias any type, not just named types. That means you can create semantic aliases for tuple types, array types, pointer types, or other unsafe types. For more information, see the [feature specification](~/_csharplang/proposals/using-alias-types.md). + +## Inline arrays + +Inline arrays are used by the runtime team and other library authors to improve performance in your apps. Inline arrays enable a developer to create an array of fixed size in a `struct` type. A struct with an inline buffer should provide performance characteristics similar to an unsafe fixed size buffer. You likely won't declare your own inline arrays, but you'll use them transparently when they're exposed as or objects from runtime APIs. + +An *inline array* is declared similar to the following `struct`: + +```csharp +[System.Runtime.CompilerServices.InlineArray(10)] +public struct Buffer +{ + private int _element0; +} +``` + +You use them like any other array: + +```csharp +var buffer = new Buffer(); +for (int i = 0; i < 10; i++) +{ + buffer[i] = i; +} + +foreach (var i in buffer) +{ + Console.WriteLine(i); +} +``` + +The difference is that the compiler can take advantage of known information about an inline array. You'll likely consume inline arrays as you would any other array. For more information on how to declare inline arrays, see the language reference on [`struct` types](../language-reference/builtin-types/struct.md#inline-arrays). ## Interceptors @@ -37,11 +69,11 @@ You can use the `using` alias directive to alias any type, not just named types. > > In order to use interceptors, you'll need to set the `InterceptorsPreview` element in your project file. Without this flag, interceptors are disabled, even when other C# 12 features are enabled. -An *interceptor* is a method which can declaratively substitute a call to an *interceptable* method with a call to itself at compile time. This substitution occurs by having the interceptor declare the source locations of the calls that it intercepts. This provides a limited facility to change the semantics of existing code by adding new code to a compilation, for example in a source generator. +An *interceptor* is a method that can declaratively substitute a call to an *interceptable* method with a call to itself at compile time. This substitution occurs by having the interceptor declare the source locations of the calls that it intercepts. Interceptors provides a limited facility to change the semantics of existing code by adding new code to a compilation, for example in a source generator. You use an *interceptor* as part of a source generator to modify, rather than add code to an existing source compilation. The source generator substitutes calls to an interceptable method with a call to the *interceptor* method. -If you are interested in experimenting with interceptors, you can learn more by reading the [feature specification](https://github.com/dotnet/roslyn/blob/main/docs/features/interceptors.md). If you use the feature, make sure to stay current with any changes in the feature specification for this preview feature. Once the feature is finalized, we'll add more guidance on this site. +If you're interested in experimenting with interceptors, you can learn more by reading the [feature specification](https://github.com/dotnet/roslyn/blob/main/docs/features/interceptors.md). If you use the feature, make sure to stay current with any changes in the feature specification for this preview feature. Once the feature is finalized, we'll add more guidance on this site. ## See also diff --git a/includes/csharp10-templates.md b/includes/csharp10-templates.md index dfa4fbcde848a..d29a5b3e88840 100644 --- a/includes/csharp10-templates.md +++ b/includes/csharp10-templates.md @@ -14,3 +14,5 @@ ms.topic: include > - Microsoft.NET.Sdk.Worker > > These implicit `global using` directives include the most common namespaces for the project type. +> +> For more information, see the article on [Implicit using directives](~/docs/core/project-sdk/overview.md#implicit-using-directives) diff --git a/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideLINQ/CS/csRef30LangFeatures_2.cs b/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideLINQ/CS/csRef30LangFeatures_2.cs index 8cdb507066d9b..71757b865b6c6 100644 --- a/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideLINQ/CS/csRef30LangFeatures_2.cs +++ b/samples/snippets/csharp/VS_Snippets_VBCSharp/csProgGuideLINQ/CS/csRef30LangFeatures_2.cs @@ -304,25 +304,88 @@ public override string ToString() // class ImplicitlyTypedArraySample { - static void Main() - { - var a = new[] { 1, 10, 100, 1000 }; // int[] - var b = new[] { "hello", null, "world" }; // string[] - - // single-dimension jagged array - var c = new[] - { - new[]{1,2,3,4}, - new[]{5,6,7,8} - }; - - // jagged array of strings - var d = new[] - { - new[]{"Luca", "Mads", "Luke", "Dinesh"}, - new[]{"Karen", "Suma", "Frances"} - }; - } + static void Main() + { + var a = new[] { 1, 10, 100, 1000 }; // int[] + + // Accessing array + Console.WriteLine("First element: " + a[0]); + Console.WriteLine("Second element: " + a[1]); + Console.WriteLine("Third element: " + a[2]); + Console.WriteLine("Fourth element: " + a[3]); + /* Outputs + First element: 1 + Second element: 10 + Third element: 100 + Fourth element: 1000 + */ + + var b = new[] { "hello", null, "world" }; // string[] + + // Accessing elements of an array using 'string.Join' method + Console.WriteLine(string.Join(" ", b)); + /* Output + hello world + */ + + // single-dimension jagged array + var c = new[] + { + new[]{1,2,3,4}, + new[]{5,6,7,8} + }; + // Looping through the outer array + for (int k = 0; k < c.Length; k++) + { + // Looping through each inner array + for (int j = 0; j < c[k].Length; j++) + { + // Accessing each element and printing it to the console + Console.WriteLine($"Element at c[{k}][{j}] is: {c[k][j]}"); + } + } + /* Outputs + Element at c[0][0] is: 1 + Element at c[0][1] is: 2 + Element at c[0][2] is: 3 + Element at c[0][3] is: 4 + Element at c[1][0] is: 5 + Element at c[1][1] is: 6 + Element at c[1][2] is: 7 + Element at c[1][3] is: 8 + */ + + // jagged array of strings + var d = new[] + { + new[]{"Luca", "Mads", "Luke", "Dinesh"}, + new[]{"Karen", "Suma", "Frances"} + }; + + // Looping through the outer array + int i = 0; + foreach (var subArray in d) + { + // Looping through each inner array + int j = 0; + foreach (var element in subArray) + { + // Accessing each element and printing it to the console + Console.WriteLine($"Element at d[{i}][{j}] is: {element}"); + j++; + } + i++; + } + /* Outputs + Element at d[0][0] is: Luca + Element at d[0][1] is: Mads + Element at d[0][2] is: Luke + Element at d[0][3] is: Dinesh + Element at d[1][0] is: Karen + Element at d[1][1] is: Suma + Element at d[1][2] is: Frances + */ + } } //