Skip to content

Commit

Permalink
edit pass, address open issues
Browse files Browse the repository at this point in the history
Address open issues on all affected articles, perform a general edit pass.
  • Loading branch information
BillWagner committed Jul 26, 2024
1 parent 14ffe1b commit c8c8642
Show file tree
Hide file tree
Showing 8 changed files with 57 additions and 24 deletions.
4 changes: 2 additions & 2 deletions docs/csharp/language-reference/attributes/general.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: "Attributes interpreted by the compiler: Miscellaneous"
ms.date: 10/26/2023
ms.date: 07/26/2024
description: "Learn about attributes that affect code generated by the compiler: the Conditional, Obsolete, AttributeUsage, ModuleInitializer, and SkipLocalsInit attributes."
---
# Miscellaneous attributes interpreted by the C# compiler
Expand Down Expand Up @@ -128,7 +128,7 @@ You add the <xref:System.Runtime.CompilerServices.AsyncMethodBuilderAttribute?di
* Has an accessible `GetAwaiter` method.
* The object returned by the `GetAwaiter` method implements the <xref:System.Runtime.CompilerServices.ICriticalNotifyCompletion?displayProperty=nameWithType> interface.

The constructor to the `AsyncMethodBuilder` attribute specifies the type of the associated builder. The builder must implement the following accessible members:
The constructor to the `AsyncMethodBuilder` attribute specifies the type of the associated builder. The builder must implement the following accessible members:

* A static `Create()` method that returns the type of the builder.
* A readable `Task` property that returns the async return type.
Expand Down
6 changes: 3 additions & 3 deletions docs/csharp/language-reference/attributes/global.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: "Attributes interpreted by the compiler: Global attributes"
ms.date: 12/16/2020
ms.date: 07/26/2024
description: Attributes provide metadata the compiler uses to understand more semantics of your program
---
# Assembly level attributes interpreted by the C# compiler
Expand Down Expand Up @@ -29,11 +29,11 @@ The following table shows the identity attributes.
|---------------|-------------|
|<xref:System.Reflection.AssemblyVersionAttribute>|Specifies the version of an assembly.|
|<xref:System.Reflection.AssemblyCultureAttribute>|Specifies which culture the assembly supports.|
|<xref:System.Reflection.AssemblyFlagsAttribute>|Specifies whether an assembly supports side-by-side execution on the same computer, in the same process, or in the same application domain.|
|<xref:System.Reflection.AssemblyFlagsAttribute>|Specifies a bitwise combination of flags for an assembly, describing just-in-time (JIT) compiler options, whether the assembly is retargetable, and whether it has a full or tokenized public key. |

## Informational attributes

You use informational attributes to provide additional company or product information for an assembly. The following table shows the informational attributes defined in the <xref:System.Reflection?displayProperty=nameWithType> namespace.
You use informational attributes to provide more company or product information for an assembly. The following table shows the informational attributes defined in the <xref:System.Reflection?displayProperty=nameWithType> namespace.

|Attribute|Purpose|
|---------------|-------------|
Expand Down
8 changes: 4 additions & 4 deletions docs/csharp/language-reference/builtin-types/ref-struct.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "ref struct types"
description: Learn about the ref struct type in C#
ms.date: 06/28/2024
ms.date: 07/26/2024
---
# `ref` structure types (C# reference)

Expand Down Expand Up @@ -60,16 +60,16 @@ The `Span<T>` type stores a reference through which it accesses the contiguous e

You can define a disposable `ref struct`. To do that, ensure that a `ref struct` fits the [disposable pattern](~/_csharplang/proposals/csharp-8.0/using.md#pattern-based-using). That is, it has an instance `Dispose` method, which is accessible, parameterless and has a `void` return type. You can use the [using statement or declaration](../statements/using.md) with an instance of a disposable `ref struct`.

Beginning with C# 13, you can also implement the <xref:System.IDisposable?displayName=nameWithType> on `ref struct` types. However, overload resolution prefers the disposable pattern to the interface method. Only if a suitable `Dispose` method isn't found will an `IDisposable.Dispose` method be chosen.
Beginning with C# 13, you can also implement the <xref:System.IDisposable?displayName=nameWithType> on `ref struct` types. However, overload resolution prefers the disposable pattern to the interface method. The compiler resolves to an `IDisposable.Dispose` method only whan a suitable `Dispose` method isn't found.

## Restrictions for `ref struct` types that implement an interface

These restrictions ensure that a `ref struct` type that implements an interface obeys the necessary [ref safety](~/_csharpstandard/standard/structs.md#1623-ref-modifier) rules.

- A `ref struct` can't be converted to an instance of an interface it implements. This includes the implicit conversion when you use a `ref struct` type as an argument when the parameter is an interface type. The conversion results in a boxing conversion, which violates ref safety.
- A `ref struct` can't be converted to an instance of an interface it implements. This restriction includes the implicit conversion when you use a `ref struct` type as an argument when the parameter is an interface type. The conversion results in a boxing conversion, which violates ref safety.
- A `ref struct` that implements an interface *must* implement all interface members. The `ref struct` must implement members where the interface includes a default implementation.

The compiler enforces these restrictions. If you write `ref struct` types that implement interfaces, each new update may include new [default interface members](../keywords/interface.md#default-interface-members). Until you provide an implementation for these new methods, your application won't compile.
The compiler enforces these restrictions. If you write `ref struct` types that implement interfaces, each new update might include new [default interface members](../keywords/interface.md#default-interface-members). Until you provide an implementation for these new methods, your application won't compile.

> [!IMPORTANT]
> A `ref struct` that implements an interface includes the potential for later source-breaking and binary-breaking changes. The break occurs if a `ref struct` implements an interface defined in another assembly, and that assembly provides an update which adds default members to that interface.
Expand Down
12 changes: 10 additions & 2 deletions docs/csharp/language-reference/keywords/interface.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
description: "Use the `interface` keyword to define contracts that any implementing type must support. Interfaces provide the means to create common behavior among a set of unrelated types."
title: "interface keyword"
ms.date: 07/08/2022
ms.date: 07/26/2024
f1_keywords:
- "interface_CSharpKeyword"
helpviewer_keywords:
Expand All @@ -15,6 +15,10 @@ In the following example, class `ImplementationClass` must implement a method na

For more information and examples, see [Interfaces](../../fundamentals/types/interfaces.md).

A top-level interface, one declared in a namespace but not nested inside another type, can be declared `public` or `internal`. The default is `internal`. Nested interface declarations, those nested inside another type, can be declared using any access modifier.

Interface members without an implementation can't include an access modifier. Members with a default implementation can include any access modifier.

## Example interface

[!code-csharp[csrefKeywordsTypes#14](~/samples/snippets/csharp/VS_Snippets_VBCSharp/csrefKeywordsTypes/CS/keywordsTypes.cs#14)]
Expand Down Expand Up @@ -63,7 +67,11 @@ public interface INamed
}
```

An interface can inherit from one or more base interfaces. When an interface [overrides a method](override.md) implemented in a base interface, it must use the [explicit interface implementation](../../programming-guide/interfaces/explicit-interface-implementation.md) syntax.
An interface can inherit from one or more base interfaces. When an interface inherits from another interface, a type implementing the derived interface must implement all the members in the base interfaces as well as those declared in the derived interface, as shown in the following code:

:::code language="csharp" source="./snippets/DefineTypes.cs" id="SnippetDerivedInterfaces":::

When an interface [overrides a method](override.md) implemented in a base interface, it must use the [explicit interface implementation](../../programming-guide/interfaces/explicit-interface-implementation.md) syntax.

When a base type list contains a base class and interfaces, the base class must come first in the list.

Expand Down
20 changes: 20 additions & 0 deletions docs/csharp/language-reference/keywords/snippets/DefineTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,23 @@ static void Main()
}
// Output: My Point: x=2, y=3
//</snippet15>

// <SnippetDerivedInterfaces>
public interface I1
{
void M1();
}

public interface I2 : I1
{
void M2;
}

public class C : I2
{
// implements I1.M1
public void M1() { }
// implements I2.M2
public void M2() { }
}
// </SnippetDerivedInterfaces>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
description: "where (generic type constraint) - C# Reference"
title: "where (generic type constraint)"

ms.date: 04/28/2021
ms.date: 07/26/2024
f1_keywords:
- "whereconstraint"
- "whereconstraint_CSharpKeyword"
Expand All @@ -28,17 +28,17 @@ The `where` clause can also include a base class constraint. The base class cons

:::code language="csharp" source="snippets/GenericWhereConstraints.cs" ID="Snippet2":::

In a nullable context, the nullability of the base class type is enforced. If the base class is non-nullable (for example `Base`), the type argument must be non-nullable. If the base class is nullable (for example `Base?`), the type argument may be either a nullable or non-nullable reference type. The compiler issues a warning if the type argument is a nullable reference type when the base class is non-nullable.
In a nullable context, the nullability of the base class type is enforced. If the base class is non-nullable (for example `Base`), the type argument must be non-nullable. If the base class is nullable (for example `Base?`), the type argument can be either a nullable or non-nullable reference type. The compiler issues a warning if the type argument is a nullable reference type when the base class is non-nullable.

The `where` clause can specify that the type is a `class` or a `struct`. The `struct` constraint removes the need to specify a base class constraint of `System.ValueType`. The `System.ValueType` type may not be used as a base class constraint. The following example shows both the `class` and `struct` constraints:
The `where` clause can specify that the type is a `class` or a `struct`. The `struct` constraint removes the need to specify a base class constraint of `System.ValueType`. The `System.ValueType` type can't be used as a base class constraint. The following example shows both the `class` and `struct` constraints:

:::code language="csharp" source="snippets/GenericWhereConstraints.cs" ID="Snippet3":::

In a nullable context, the `class` constraint requires a type to be a non-nullable reference type. To allow nullable reference types, use the `class?` constraint, which allows both nullable and non-nullable reference types.

The `where` clause may include the `notnull` constraint. The `notnull` constraint limits the type parameter to non-nullable types. The type may be a [value type](../builtin-types/value-types.md) or a non-nullable reference type. The `notnull` constraint is available for code compiled in a [`nullable enable` context](../../nullable-references.md#nullable-contexts). Unlike other constraints, if a type argument violates the `notnull` constraint, the compiler generates a warning instead of an error. Warnings are only generated in a `nullable enable` context.
The `where` clause can include the `notnull` constraint. The `notnull` constraint limits the type parameter to non-nullable types. The type can be a [value type](../builtin-types/value-types.md) or a non-nullable reference type. The `notnull` constraint is available for code compiled in a [`nullable enable` context](../../nullable-references.md#nullable-contexts). Unlike other constraints, if a type argument violates the `notnull` constraint, the compiler generates a warning instead of an error. Warnings are only generated in a `nullable enable` context.

The addition of nullable reference types introduces a potential ambiguity in the meaning of `T?` in generic methods. If `T` is a `struct`, `T?` is the same as <xref:System.Nullable%601?displayProperty=nameWithType>. However, if `T` is a reference type, `T?` means that `null` is a valid value. The ambiguity arises because overriding methods can't include constraints. The new `default` constraint resolves this ambiguity. You'll add it when a base class or interface declares two overloads of a method, one that specifies the `struct` constraint, and one that doesn't have either the `struct` or `class` constraint applied:
The addition of nullable reference types introduces a potential ambiguity in the meaning of `T?` in generic methods. If `T` is a `struct`, `T?` is the same as <xref:System.Nullable%601?displayProperty=nameWithType>. However, if `T` is a reference type, `T?` means that `null` is a valid value. The ambiguity arises because overriding methods can't include constraints. The new `default` constraint resolves this ambiguity. You add it when a base class or interface declares two overloads of a method, one that specifies the `struct` constraint, and one that doesn't have either the `struct` or `class` constraint applied:

:::code language="csharp" source="snippets/GenericWhereConstraints.cs" ID="BaseClass":::

Expand All @@ -51,15 +51,15 @@ You use the `default` constraint to specify that your derived class overrides th
:::code language="csharp" source="snippets/GenericWhereConstraints.cs" ID="NotNull":::

The `where` clause may also include an `unmanaged` constraint. The `unmanaged` constraint limits the type parameter to types known as [unmanaged types](../builtin-types/unmanaged-types.md). The `unmanaged` constraint makes it easier to write low-level interop code in C#. This constraint enables reusable routines across all unmanaged types. The `unmanaged` constraint can't be combined with the `class` or `struct` constraint. The `unmanaged` constraint enforces that the type must be a `struct`:
The `where` clause can also include an `unmanaged` constraint. The `unmanaged` constraint limits the type parameter to types known as [unmanaged types](../builtin-types/unmanaged-types.md). The `unmanaged` constraint makes it easier to write low-level interop code in C#. This constraint enables reusable routines across all unmanaged types. The `unmanaged` constraint can't be combined with the `class` or `struct` constraint. The `unmanaged` constraint enforces that the type must be a `struct`:

:::code language="csharp" source="snippets/GenericWhereConstraints.cs" ID="Snippet4":::

The `where` clause may also include a constructor constraint, `new()`. That constraint makes it possible to create an instance of a type parameter using the `new` operator. The [new() Constraint](new-constraint.md) lets the compiler know that any type argument supplied must have an accessible parameterless constructor. For example:
The `where` clause can also include a constructor constraint, `new()`. That constraint makes it possible to create an instance of a type parameter using the `new` operator. The [new() Constraint](new-constraint.md) lets the compiler know that any type argument supplied must have an accessible parameterless constructor. For example:

:::code language="csharp" source="snippets/GenericWhereConstraints.cs" ID="Snippet5":::

The `new()` constraint appears last in the `where` clause, unless it is followed by the `allows ref struct` anti-constraint. The `new()` constraint can't be combined with the `struct` or `unmanaged` constraints. All types satisfying those constraints must have an accessible parameterless constructor, making the `new()` constraint redundant.
The `new()` constraint appears last in the `where` clause, unless it's followed by the `allows ref struct` anti-constraint. The `new()` constraint can't be combined with the `struct` or `unmanaged` constraints. All types satisfying those constraints must have an accessible parameterless constructor, making the `new()` constraint redundant.

This anti-constraint declares that the type argument for `T` can be a `ref struct` type. For example:

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Constraints on type parameters"
description: Learn about constraints on type parameters. Constraints tell the compiler what capabilities a type argument must have.
ms.date: 03/11/2024
ms.date: 07/26/2024
f1_keywords:
- "defaultconstraint_CSharpKeyword"
- "notnull_CSharpKeyword"
Expand Down Expand Up @@ -35,7 +35,7 @@ Constraints inform the compiler about the capabilities a type argument must have
Some constraints are mutually exclusive, and some constraints must be in a specified order:

- You can apply at most one of the `struct`, `class`, `class?`, `notnull`, and `unmanaged` constraints. If you supply any of these constraints, it must be the first constraint specified for that type parameter.
- The base class constraint, (`where T : Base` or `where T : Base?`), can't be combined with any of the constraints `struct`, `class`, `class?`, `notnull`, or `unmanaged`.
- The base class constraint (`where T : Base` or `where T : Base?`) can't be combined with any of the constraints `struct`, `class`, `class?`, `notnull`, or `unmanaged`.
- You can apply at most one base class constraint, in either form. If you want to support the nullable base type, use `Base?`.
- You can't name both the non-nullable and nullable form of an interface as a constraint.
- The `new()` constraint can't be combined with the `struct` or `unmanaged` constraint. If you specify the `new()` constraint, it must be the last constraint for that type parameter. Anti-constraints, if applicable, can follow the `new()` constraint.
Expand Down Expand Up @@ -121,11 +121,11 @@ You can use <xref:System.Delegate?displayProperty=nameWithType> or <xref:System.

:::code language="csharp" source="./snippets/GenericWhereConstraints.cs" id="Snippet16":::

You can use the above method to combine delegates that are the same type:
You can use the preceding method to combine delegates that are the same type:

:::code language="csharp" source="./snippets/GenericWhereConstraints.cs" id="Snippet17":::

If you uncomment the last line, it won't compile. Both `first` and `test` are delegate types, but they're different delegate types.
If you uncomment the last line, it doesn't compile. Both `first` and `test` are delegate types, but they're different delegate types.

## Enum constraints

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,14 @@ public interface IEmployee
}

// <Snippet10>
class EmployeeList<T> where T : Employee, System.Collections.Generic.IList<T>, IDisposable, new()
class EmployeeList<T> where T : notnull, Employee, IComparable<T>, new()
{
// ...
public void AddDefault()
{
T t = new T();
// ...
}
}
// </Snippet10>

Expand Down

0 comments on commit c8c8642

Please sign in to comment.