From 65c07f523b1b337087cde59efb1662757e78f9fa Mon Sep 17 00:00:00 2001 From: Cam Soper Date: Mon, 13 Apr 2020 19:47:46 -0500 Subject: [PATCH 01/14] Removed old ASR link, added VM migration links --- docs/azure/migration/vm.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/azure/migration/vm.md b/docs/azure/migration/vm.md index b994e27a4483b..52cc1924185ee 100644 --- a/docs/azure/migration/vm.md +++ b/docs/azure/migration/vm.md @@ -17,9 +17,10 @@ Learn how to create a virtual machine and publish your app to it: [Publish to an These tutorials demonstrate the steps to create (or migrate) a virtual machine, publish your web application to it, and other tasks that may be required to support your application in Azure. -- Create a virtual machine for your ASP.NET application in Azure using one of the following two options: +- Create a virtual machine for your ASP.NET application in Azure using one of the following options: - [Create a new virtual machine for ASP.NET Applications](https://go.microsoft.com/fwlink/?linkid=863237) - - [Migrate an existing on-premises virtual machine](https://docs.microsoft.com/azure/site-recovery/tutorial-migrate-on-premises-to-azure) + - [Migrate an existing on-premises VMWare virtual machine](https://docs.microsoft.com/azure/migrate/tutorial-migrate-vmware) + - [Migrate an existing on-premises Hyper-V virtual machine](https://docs.microsoft.com/azure/migrate/tutorial-migrate-hyper-v) - [Publish your app using Visual Studio](https://go.microsoft.com/fwlink/?linkid=863240) - [Create a secure virtual network for your VMs](https://docs.microsoft.com/azure/virtual-network/virtual-network-get-started-vnet-subnet) - [Create a CI/CD pipeline for your application](https://docs.microsoft.com/vsts/build-release/apps/cd/deploy-webdeploy-iis-deploygroups) From 88f94e56fc51e17de2ba05d327b682287eeaa121 Mon Sep 17 00:00:00 2001 From: Scott Hussey Date: Tue, 14 Apr 2020 10:09:55 -0500 Subject: [PATCH 02/14] Align version in sample with narrative (#17836) The narrative is about building a Netcore 3.1 app, but the sample showed 2.2. --- .../cli-create-console-app/HelloMsBuild/csharp/Hello.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/snippets/core/tutorials/cli-create-console-app/HelloMsBuild/csharp/Hello.csproj b/samples/snippets/core/tutorials/cli-create-console-app/HelloMsBuild/csharp/Hello.csproj index c52b93a21fbc7..9acff6d2afa81 100644 --- a/samples/snippets/core/tutorials/cli-create-console-app/HelloMsBuild/csharp/Hello.csproj +++ b/samples/snippets/core/tutorials/cli-create-console-app/HelloMsBuild/csharp/Hello.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp2.2 + netcoreapp3.1 - \ No newline at end of file + From 06c5a1c97b2c0de482dba3d5174456595f8d97eb Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 14 Apr 2020 11:19:57 -0400 Subject: [PATCH 03/14] Reorganize and update language reference for attributes processed by the C# compiler, including nullable analysis (#17776) * Create outlines for new content - update TOC - Add stub outlines for new content. * port global attribute content * port general attributes - Add description for general attributes - Move samples from /samples/snippets - Add interactivity where possible. * remove links, move existing content. * fix a build warning * fix warnings * off by one folder * finished updating caller information * move existing nullable attribute content Also, update the title of the existing content * proofread and add new attributes * fix titles * Apply suggestions from code review Co-Authored-By: Petr Kulikov * fix build warnings. Co-authored-by: Petr Kulikov --- .openpublishing.redirection.json | 12 + .../attributes/caller-information.md | 69 +++++ .../language-reference/attributes/general.md | 98 ++++++ .../language-reference/attributes/global.md | 57 ++++ .../attributes/nullable-analysis.md | 288 ++++++++++++++++++ .../snippets/ConditionalExamples.cs | 46 +++ .../attributes/snippets}/MultiUseAttribute.cs | 8 +- .../attributes/snippets/NewAttribute.cs | 21 ++ .../snippets}/NewPropertyOrFieldAttribute.cs | 12 +- .../snippets}/NonInheritedAttribute.cs | 6 +- .../attributes/snippets/ObsoleteExample.cs | 35 +++ .../attributes/snippets/Program.cs | 13 + .../attributes/snippets/attributes.csproj | 9 + .../attributes/snippets/trace.cs | 24 ++ .../compiler-messages/cs0579.md | 2 +- docs/csharp/nullable-attributes.md | 214 +------------ .../concepts/attributes/attributeusage.md | 85 ------ .../concepts/attributes/common-attributes.md | 233 -------------- .../attributes/creating-custom-attributes.md | 2 +- .../concepts/attributes/index.md | 4 +- .../concepts/caller-information.md | 81 ----- .../programming-guide/concepts/index.md | 1 - docs/csharp/toc.yml | 21 +- .../whats-new/csharp-version-history.md | 2 +- ...ise-change-notifications--bindingsource.md | 2 +- .../csharp/attributes/NewAttribute.cs | 23 -- 26 files changed, 703 insertions(+), 665 deletions(-) create mode 100644 docs/csharp/language-reference/attributes/caller-information.md create mode 100644 docs/csharp/language-reference/attributes/general.md create mode 100644 docs/csharp/language-reference/attributes/global.md create mode 100644 docs/csharp/language-reference/attributes/nullable-analysis.md create mode 100644 docs/csharp/language-reference/attributes/snippets/ConditionalExamples.cs rename {samples/snippets/csharp/attributes => docs/csharp/language-reference/attributes/snippets}/MultiUseAttribute.cs (66%) create mode 100644 docs/csharp/language-reference/attributes/snippets/NewAttribute.cs rename {samples/snippets/csharp/attributes => docs/csharp/language-reference/attributes/snippets}/NewPropertyOrFieldAttribute.cs (69%) rename {samples/snippets/csharp/attributes => docs/csharp/language-reference/attributes/snippets}/NonInheritedAttribute.cs (71%) create mode 100644 docs/csharp/language-reference/attributes/snippets/ObsoleteExample.cs create mode 100644 docs/csharp/language-reference/attributes/snippets/Program.cs create mode 100644 docs/csharp/language-reference/attributes/snippets/attributes.csproj create mode 100644 docs/csharp/language-reference/attributes/snippets/trace.cs delete mode 100644 docs/csharp/programming-guide/concepts/attributes/attributeusage.md delete mode 100644 docs/csharp/programming-guide/concepts/attributes/common-attributes.md delete mode 100644 docs/csharp/programming-guide/concepts/caller-information.md delete mode 100644 samples/snippets/csharp/attributes/NewAttribute.cs diff --git a/.openpublishing.redirection.json b/.openpublishing.redirection.json index 4d1299f6d2dec..3ec4287ec8d07 100644 --- a/.openpublishing.redirection.json +++ b/.openpublishing.redirection.json @@ -1081,6 +1081,10 @@ "source_path": "docs/csharp/programming-guide/arrays/passing-arrays-using-ref-and-out.md", "redirect_url": "/dotnet/csharp/programming-guide/arrays" }, + { + "source_path": "docs/csharp/programming-guide/concepts/caller-information.md", + "redirect_url": "/dotnet/csharp/language-reference/attributes/caller-information" + }, { "source_path": "docs/csharp/programming-guide/classes-and-structs/how-to-access-a-collection-class-with-foreach.md", "redirect_url": "/dotnet/csharp/language-reference/keywords/foreach-in" @@ -1139,6 +1143,14 @@ "source_path": "docs/csharp/programming-guide/concepts/async/asynchronous-programming-with-async-and-await.md", "redirect_url": "/dotnet/csharp/async/" }, + { + "source_path": "docs/csharp/programming-guide/concepts/attributes/attributeusage.md", + "redirect_url": "/dotnet/csharp/language-reference/attributes/general" + }, + { + "source_path": "docs/csharp/programming-guide/concepts/attributes/common-attributes.md", + "redirect_url": "/dotnet/csharp/language-reference/attributes/global" + }, { "source_path": "docs/csharp/programming-guide/concepts/linq/advanced-query-techniques-linq-to-xml.md", "redirect_url": "/dotnet/csharp/programming-guide/concepts/linq/how-to-join-two-collections-linq-to-xml" diff --git a/docs/csharp/language-reference/attributes/caller-information.md b/docs/csharp/language-reference/attributes/caller-information.md new file mode 100644 index 0000000000000..5b93a3997ac03 --- /dev/null +++ b/docs/csharp/language-reference/attributes/caller-information.md @@ -0,0 +1,69 @@ +--- +title: "C# Reserved attributes: Tracking caller information" +ms.date: 04/09/2020 +description: These attributes instruct the compiler to generate information about the code that calls a member. You use the CallerFilePath, CallerLineNumber, and CallerMemberName to provide detailed trace information +--- + +# Reserved attributes: Determine caller information + +Using info attributes, you obtain information about the caller to a method. You obtain the file path of the source code, the line number in the source code, and the member name of the caller. To obtain member caller information, you use attributes that are applied to optional parameters. Each optional parameter specifies a default value. The following table lists the Caller Info attributes that are defined in the namespace: + +|Attribute|Description|Type| +|---|---|---| +||Full path of the source file that contains the caller. The full path is the path at compile time.|`String`| +||Line number in the source file from which the method is called.|`Integer`| +||Method name or property name of the caller.|`String`| + +This information helps you write tracing, debugging, and create diagnostic tools. The following example shows how to use caller info attributes. On each call to the `TraceMessage` method, the caller information is substituted as arguments to the optional parameters. + +```csharp +public void DoProcessing() +{ + TraceMessage("Something happened."); +} + +public void TraceMessage(string message, + [CallerMemberName] string memberName = "", + [CallerFilePath] string sourceFilePath = "", + [CallerLineNumber] int sourceLineNumber = 0) +{ + Trace.WriteLine("message: " + message); + Trace.WriteLine("member name: " + memberName); + Trace.WriteLine("source file path: " + sourceFilePath); + Trace.WriteLine("source line number: " + sourceLineNumber); +} + +// Sample Output: +// message: Something happened. +// member name: DoProcessing +// source file path: c:\Visual Studio Projects\CallerInfoCS\CallerInfoCS\Form1.cs +// source line number: 31 +``` + +You specify an explicit default value for each optional parameter. You can't apply caller info attributes to parameters that aren't specified as optional. The caller info attributes don't make a parameter optional. Instead, they affect the default value that's passed in when the argument is omitted. Caller info values are emitted as literals into the Intermediate Language (IL) at compile time. Unlike the results of the property for exceptions, the results aren't affected by obfuscation. You can explicitly supply the optional arguments to control the caller information or to hide caller information. + +### Member names + +You can use the `CallerMemberName` attribute to avoid specifying the member name as a `String` argument to the called method. By using this technique, you avoid the problem that **Rename Refactoring** doesn't change the `String` values. This benefit is especially useful for the following tasks: + +- Using tracing and diagnostic routines. +- Implementing the interface when binding data. This interface allows the property of an object to notify a bound control that the property has changed, so that the control can display the updated information. Without the `CallerMemberName` attribute, you must specify the property name as a literal. + +The following chart shows the member names that are returned when you use the `CallerMemberName` attribute. + +|Calls occur within|Member name result| +|-|-| +|Method, property, or event|The name of the method, property, or event from which the call originated.| +|Constructor|The string ".ctor"| +|Static constructor|The string ".cctor"| +|Destructor|The string "Finalize"| +|User-defined operators or conversions|The generated name for the member, for example, "op_Addition".| +|Attribute constructor|The name of the method or property to which the attribute is applied. If the attribute is any element within a member (such as a parameter, a return value, or a generic type parameter), this result is the name of the member that's associated with that element.| +|No containing member (for example, assembly-level or attributes that are applied to types)|The default value of the optional parameter.| + +## See also + +- [Named and Optional Arguments](../../programming-guide/classes-and-structs/named-and-optional-arguments.md) +- +- +- [Attributes](../../../standard/attributes/index.md) diff --git a/docs/csharp/language-reference/attributes/general.md b/docs/csharp/language-reference/attributes/general.md new file mode 100644 index 0000000000000..78fc49e7aa90e --- /dev/null +++ b/docs/csharp/language-reference/attributes/general.md @@ -0,0 +1,98 @@ +--- +title: "C# reserved attributes: Conditional, Obsolete, AttributeUsage" +ms.date: 04/09/2020 +description: These attributes are interpreted by the compiler to affect the code generated by the compiler +--- +# Reserved attributes: ConditionalAttribute, ObsoleteAttribute, AttributeUsageAttribute + +These attributes can be applied to elements in your code. They add semantic meaning to those elements. The compiler uses those semantic meanings to alter its output and report possible mistakes by developers using your code. + +## `Conditional` attribute + +The `Conditional` attribute makes the execution of a method dependent on a preprocessing identifier. The `Conditional` attribute is an alias for , and can be applied to a method or an attribute class. + +In the following example, `Conditional` is applied to a method to enable or disable the display of program-specific diagnostic information: + +::::::code language="csharp" source="snippets/trace.cs" interactive="try-dotnet" ::: + +If the `TRACE_ON` identifier isn't defined, the trace output isn't displayed. Explore for yourself in the interactive window. + +The `Conditional` attribute is often used with the `DEBUG` identifier to enable trace and logging features for debug builds but not in release builds, as shown in the following example: + +::::::code language="csharp" source="snippets/ConditionalExamples.cs" id="SnippetConditional" ::: + +When a method marked conditional is called, the presence or absence of the specified preprocessing symbol determines whether the call is included or omitted. If the symbol is defined, the call is included; otherwise, the call is omitted. A conditional method must be a method in a class or struct declaration and must have a `void` return type. Using `Conditional` is cleaner, more elegant, and less error-prone than enclosing methods inside `#if…#endif` blocks. + +If a method has multiple `Conditional` attributes, a call to the method is included if at one or more conditional symbols is defined (the symbols are logically linked together by using the OR operator). In the following example, the presence of either `A` or `B` results in a method call: + +::::::code language="csharp" source="snippets/ConditionalExamples.cs" id="SnippetMultipleConditions" ::: + +### Using `Conditional` with attribute classes + +The `Conditional` attribute can also be applied to an attribute class definition. In the following example, the custom attribute `Documentation` will only add information to the metadata if `DEBUG` is defined. + +::::::code language="csharp" source="snippets/ConditionalExamples.cs" id="SnippetConditionalConditionalAttribute" ::: + +## `Obsolete` attribute + +The `Obsolete` attribute marks a code element as no longer recommended for use. Use of an entity marked obsolete generates a warning or an error. The `Obsolete` attribute is a single-use attribute and can be applied to any entity that allows attributes. `Obsolete` is an alias for . + +In the following example the `Obsolete` attribute is applied to class `A` and to method `B.OldMethod`. Because the second argument of the attribute constructor applied to `B.OldMethod` is set to `true`, this method will cause a compiler error, whereas using class `A` will just produce a warning. Calling `B.NewMethod`, however, produces no warning or error. For example, when you use it with the previous definitions, the following code generates two warnings and one error: + +::::::code language="csharp" source="snippets/ObsoleteExample.cs" interactive="try-dotnet" ::: + +The string provided as the first argument to the attribute constructor will be displayed as part of the warning or error. Two warnings for class `A` are generated: one for the declaration of the class reference, and one for the class constructor. The `Obsolete` attribute can be used without arguments, but including an explanation what to use instead is recommended. + +## `AttributeUsage` attribute + +The `AttributeUsage` attribute determines how a custom attribute class can be used. is an attribute you apply to custom attribute definitions. The `AttributeUsage` attribute enables you to control: + +- Which program elements attribute may be applied to. Unless you restrict its usage, an attribute may be applied to any of the following program elements: + - assembly + - module + - field + - event + - method + - param + - property + - return + - type +- Whether an attribute can be applied to a single program element multiple times. +- Whether attributes are inherited by derived classes. + +The default settings look like the following example when applied explicitly: + +:::code language="csharp" source="snippets/NewAttribute.cs" id="SnippetUsageFirst" ::: + +In this example, the `NewAttribute` class can be applied to any supported program element. But it can be applied only once to each entity. The attribute is inherited by derived classes when applied to a base class. + +The and arguments are optional, so the following code has the same effect: + +:::code language="csharp" source="snippets/NewAttribute.cs" id="SnippetUsageSecond" ::: + +The first argument must be one or more elements of the enumeration. Multiple target types can be linked together with the OR operator, like the following example shows: + +:::code language="csharp" source="snippets/NewPropertyOrFieldAttribute.cs" id="SnippetDefinePropertyAttribute" ::: + +Beginning in C# 7.3, attributes can be applied to either the property or the backing field for an auto-implemented property. The attribute applies to the property, unless you specify the `field` specifier on the attribute. Both are shown in the following example: + +:::code language="csharp" source="snippets/NewPropertyOrFieldAttribute.cs" id="SnippetUsePropertyAttribute" ::: + +If the argument is `true`, then the resulting attribute can be applied more than once to a single entity, as shown in the following example: + +:::code language="csharp" source="snippets/MultiUseAttribute.cs" id="SnippetMultiUse" ::: + +In this case, `MultiUseAttribute` can be applied repeatedly because `AllowMultiple` is set to `true`. Both formats shown for applying multiple attributes are valid. + +If is `false`, then the attribute isn't inherited by classes derived from an attributed class. For example: + +:::code language="csharp" source="snippets/NonInheritedAttribute.cs" id="SnippetNonInherited" ::: + +In this case `NonInheritedAttribute` isn't applied to `DClass` via inheritance. + +## See also + +- +- +- [Attributes](../../../standard/attributes/index.md) +- [Reflection](../../programming-guide/concepts/reflection.md) diff --git a/docs/csharp/language-reference/attributes/global.md b/docs/csharp/language-reference/attributes/global.md new file mode 100644 index 0000000000000..cdc102855a61c --- /dev/null +++ b/docs/csharp/language-reference/attributes/global.md @@ -0,0 +1,57 @@ +--- +title: "C# reserved attributes: Global attributes" +ms.date: 04/09/2020 +description: Attributes provide metadata the compiler uses to understand more semantics of your program +--- +# Reserved attributes: Assembly level attributes + +Most attributes are applied to specific language elements such as classes or methods; however, some attributes are global—they apply to an entire assembly or module. For example, the attribute can be used to embed version information into an assembly, like this: + +```csharp +[assembly: AssemblyVersion("1.0.0.0")] +``` + +Global attributes appear in the source code after any top level `using` directives and before any type, module, or namespace declarations. Global attributes can appear in multiple source files, but the files must be compiled in a single compilation pass. Visual Studio adds global attributes to the AssemblyInfo.cs file in .NET Framework projects. These attributes aren't added to .NET Core projects. + +Assembly attributes are values that provide information about an assembly. They fall into the following categories: + +- Assembly identity attributes +- Informational attributes +- Assembly manifest attributes + +## Assembly identity attributes + +Three attributes (with a strong name, if applicable) determine the identity of an assembly: name, version, and culture. These attributes form the full name of the assembly and are required when you reference it in code. You can set an assembly's version and culture using attributes. However, the name value is set by the compiler, the Visual Studio IDE in the [Assembly Information Dialog Box](/visualstudio/ide/reference/assembly-information-dialog-box), or the Assembly Linker (Al.exe) when the assembly is created. The assembly name is based on the assembly manifest. The attribute specifies whether multiple copies of the assembly can coexist. + +The following table shows the identity attributes. + +|Attribute|Purpose| +|---------------|-------------| +||Specifies the version of an assembly.| +||Specifies which culture the assembly supports.| +||Specifies whether an assembly supports side-by-side execution on the same computer, in the same process, or in the same application domain.| + +## 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 namespace. + +|Attribute|Purpose| +|---------------|-------------| +||Specifies a product name for an assembly manifest.| +||Specifies a trademark for an assembly manifest.| +||Specifies an informational version for an assembly manifest.| +||Specifies a company name for an assembly manifest.| +||Defines a custom attribute that specifies a copyright for an assembly manifest.| +||Sets a specific version number for the Win32 file version resource.| +||Indicates whether the assembly is compliant with the Common Language Specification (CLS).| + +## Assembly manifest attributes + +You can use assembly manifest attributes to provide information in the assembly manifest. The attributes include title, description, default alias, and configuration. The following table shows the assembly manifest attributes defined in the namespace. + +|Attribute|Purpose| +|---------------|-------------| +||Specifies an assembly title for an assembly manifest.| +||Specifies an assembly description for an assembly manifest.| +||Specifies an assembly configuration (such as retail or debug) for an assembly manifest.| +||Defines a friendly default alias for an assembly manifest| diff --git a/docs/csharp/language-reference/attributes/nullable-analysis.md b/docs/csharp/language-reference/attributes/nullable-analysis.md new file mode 100644 index 0000000000000..8165b9924892b --- /dev/null +++ b/docs/csharp/language-reference/attributes/nullable-analysis.md @@ -0,0 +1,288 @@ +--- +title: "C# Reserved attributes: Nullable static analysis" +ms.date: 04/14/2020 +description: These attributes are interpreted by the compiler to provide better static analysis for nullable and non-nullable reference types. +--- +# Reserved attributes contribute to the compiler's null state static analysis + +In a nullable context, the compiler performs static analysis of code to determine the null state of all reference type variables: + +- *not null*: Static analysis determined that the variable is assigned to a non-null value. +- *maybe null*: Static analysis cannot determine that a variable is assigned a non-null value. + +You can apply a number of attributes that provide information to the compiler about the semantics of your APIs. That information helps the compiler perform static analysis and determine when a variable is not null. This article provides a brief description of each of those attributes and how to use them. All the examples assume C# 8.0 or newer, and the code is in a nullable context. + +Let's start with a familiar example. Imagine your library has the following API to retrieve a resource string: + +```csharp +bool TryGetMessage(string key, out string message) +``` + +The preceding example follows the familiar `Try*` pattern in .NET. There are two reference arguments for this API: the `key` and the `message` parameter. This API has the following rules relating to the nullness of these arguments: + +- Callers shouldn't pass `null` as the argument for `key`. +- Callers can pass a variable whose value is `null` as the argument for `message`. +- If the `TryGetMessage` method returns `true`, the value of `message` isn't null. If the return value is `false,` the value of `message` (and its null state) is null. + +The rule for `key` can be expressed by the variable type: `key` should be a non-nullable reference type. The `message` parameter is more complex. It allows `null` as the argument, but guarantees that, on success, that `out` argument isn't null. For these scenarios, you need a richer vocabulary to describe the expectations. + +Several attributes have been added to express additional information about the null state of variables. All code you wrote before C# 8 introduced nullable reference types was *null oblivious*. That means any reference type variable may be null, but null checks aren't required. Once your code is *nullable aware*, those rules change. Reference types should never be the `null` value, and nullable reference types must be checked against `null` before being dereferenced. + +The rules for your APIs are likely more complicated, as you saw with the `TryGetValue` API scenario. Many of your APIs have more complex rules for when variables can or can't be `null`. In these cases, you'll use one of the following attributes to express those rules: + +- [AllowNull](xref:System.Diagnostics.CodeAnalysis.AllowNullAttribute): A non-nullable input argument may be null. +- [DisallowNull](xref:System.Diagnostics.CodeAnalysis.DisallowNullAttribute): A nullable input argument should never be null. +- [MaybeNull](xref:System.Diagnostics.CodeAnalysis.MaybeNullAttribute): A non-nullable return value may be null. +- [NotNull](xref:System.Diagnostics.CodeAnalysis.NotNullAttribute): A nullable return value will never be null. +- [MaybeNullWhen](xref:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute): A non-nullable input argument may be null when the method returns the specified `bool` value. +- [NotNullWhen](xref:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute): A nullable input argument will not be null when the method returns the specified `bool` value. +- [NotNullIfNotNull](xref:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute): A return value isn't null if the argument for the specified parameter isn't null. +- [DoesNotReturn](xref:System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute): A method never returns. In other words, it always throws an exception. +- [DoesNotReturnIf](xref:System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute): This method never returns if the associated `bool` parameter has the specified value. + +The preceding descriptions are a quick reference to what each attribute does. Each following section describes the behavior and meaning more thoroughly. + +Adding these attributes gives the compiler more information about the rules for your API. When calling code is compiled in a nullable enabled context, the compiler will warn callers when they violate those rules. These attributes don't enable additional checks on your implementation. + +## Specify preconditions: `AllowNull` and `DisallowNull` + +Consider a read/write property that never returns `null` because it has a reasonable default value. Callers pass `null` to the set accessor when setting it to that default value. For example, consider a messaging system that asks for a screen name in a chat room. If none is provided, the system generates a random name: + +```csharp +public string ScreenName +{ + get => screenName; + set => screenName = value ?? GenerateRandomScreenName(); +} +private string screenName; +``` + +When you compile the preceding code in a nullable oblivious context, everything is fine. Once you enable nullable reference types, the `ScreenName` property becomes a non-nullable reference. That's correct for the `get` accessor: it never returns `null`. Callers don't need to check the returned property for `null`. But now setting the property to `null` generates a warning. In order to continue to support this type of code, you add the attribute to the property, as shown in the following code: + +```csharp +[AllowNull] +public string ScreenName +{ + get => screenName; + set => screenName = value ?? GenerateRandomScreenName(); +} +private string screenName = GenerateRandomScreenName(); +``` + +You may need to add a `using` directive for to use this and other attributes discussed in this article. The attribute is applied to the property, not the `set` accessor. The `AllowNull` attribute specifies *pre-conditions*, and only applies to inputs. The `get` accessor has a return value, but no input arguments. Therefore, the `AllowNull` attribute only applies to the `set` accessor. + +The preceding example demonstrates what to look for when adding the `AllowNull` attribute on an argument: + +1. The general contract for that variable is that it shouldn't be `null`, so you want a non-nullable reference type. +1. There are scenarios for the input variable to be `null`, though they aren't the most common usage. + +Most often you'll need this attribute for properties, or `in`, `out`, and `ref` arguments. The `AllowNull` attribute is the best choice when a variable is typically non-null, but you need to allow `null` as a precondition. + +Contrast that with scenarios for using `DisallowNull`: You use this attribute to specify that an input variable of a nullable reference type shouldn't be `null`. Consider a property where `null` is the default value, but clients can only set it to a non-null value. Consider the following code: + +```csharp +public string ReviewComment +{ + get => _comment; + set => _comment = value ?? throw new ArgumentNullException(nameof(value), "Cannot set to null"); +} +string _comment; +``` + +The preceding code is the best way to express your design that the `ReviewComment` could be `null`, but can't be set to `null`. Once this code is nullable aware, you can express this concept more clearly to callers using the : + +```csharp +[DisallowNull] +public string? ReviewComment +{ + get => _comment; + set => _comment = value ?? throw new ArgumentNullException(nameof(value), "Cannot set to null"); +} +string? _comment; +``` + +In a nullable context, the `ReviewComment` `get` accessor could return the default value of `null`. The compiler warns that it must be checked before access. Furthermore, it warns callers that, even though it could be `null`, callers shouldn't explicitly set it to `null`. The `DisallowNull` attribute also specifies a *pre-condition*, it does not affect the `get` accessor. You use the `DisallowNull` attribute when you observe these characteristics about: + +1. The variable could be `null` in core scenarios, often when first instantiated. +1. The variable shouldn't be explicitly set to `null`. + +These situations are common in code that was originally *null oblivious*. It may be that object properties are set in two distinct initialization operations. It may be that some properties are set only after some asynchronous work has completed. + +The `AllowNull` and `DisallowNull` attributes enable you to specify that preconditions on variables may not match the nullable annotations on those variables. These provide more detail about the characteristics of your API. This additional information helps callers use your API correctly. Remember you specify preconditions using the following attributes: + +- [AllowNull](xref:System.Diagnostics.CodeAnalysis.AllowNullAttribute): A non-nullable input argument may be null. +- [DisallowNull](xref:System.Diagnostics.CodeAnalysis.DisallowNullAttribute): A nullable input argument should never be null. + +## Specify post-conditions: `MaybeNull` and `NotNull` + +Suppose you have a method with the following signature: + +```csharp +public Customer FindCustomer(string lastName, string firstName) +``` + +You've likely written a method like this to return `null` when the name sought wasn't found. The `null` clearly indicates that the record wasn't found. In this example, you'd likely change the return type from `Customer` to `Customer?`. Declaring the return value as a nullable reference type specifies the intent of this API clearly. + +For reasons covered under [Generic definitions and nullability](../../nullable-attributes.md#generic-definitions-and-nullability) that technique does not work with generic methods. You may have a generic method that follows a similar pattern: + +```csharp +public T Find(IEnumerable sequence, Func match) +``` + +You can't specify that the return value is `T?`. The method returns `null` when the sought item isn't found. Since you can't declare a `T?` return type, you add the `MaybeNull` annotation to the method return: + +```csharp +[return: MaybeNull] +public T Find(IEnumerable sequence, Func match) +``` + +The preceding code informs callers that the contract implies a non-nullable type, but the return value *may* actually be null. Use the `MaybeNull` attribute when your API should be a non-nullable type, typically a generic type parameter, but there may be instances where `null` would be returned. + +You can also specify that a return value or an `out` or `ref` argument isn't null even though the type is a nullable reference type. Consider a method that ensures an array is large enough to hold a number of elements. If the input argument doesn't have capacity, the routine would allocate a new array and copy all the existing elements into it. If the input argument is `null`, the routine would allocate new storage. If there's sufficient capacity, the routine does nothing: + +```csharp +public void EnsureCapacity(ref T[] storage, int size) +``` + +You could call this routine as follows: + +```csharp +// messages has the default value (null) when EnsureCapacity is called: +EnsureCapacity(ref messages, 10); +// messages is not null. +EnsureCapacity(messages, 50); +``` + +After enabling null reference types, you want to ensure that the preceding code compiles without warnings. When the method returns, the `storage` argument is guaranteed to be not null. However, it's acceptable to call `EnsureCapacity` with a null reference. You can make `storage` a nullable reference type, and add the `NotNull` post-condition to the parameter declaration: + +```csharp +public void EnsureCapacity([NotNull]ref T[]? storage, int size) +``` + +The preceding code expresses the existing contract clearly: Callers can pass a variable with the `null` value, but the return value is guaranteed to never be null. The `NotNull` attribute is most useful for `ref` and `out` arguments where `null` may be passed as an argument, but that argument is guaranteed to be not null when the method returns. + +You specify unconditional postconditions using the following attributes: + +- [MaybeNull](xref:System.Diagnostics.CodeAnalysis.MaybeNullAttribute): A non-nullable return value may be null. +- [NotNull](xref:System.Diagnostics.CodeAnalysis.NotNullAttribute): A nullable return value will never be null. + +## Specify conditional post-conditions: `NotNullWhen`, `MaybeNullWhen`, and `NotNullIfNotNull` + +You're likely familiar with the `string` method . This method returns `true` when the argument is null or an empty string. It's a form of null-check: Callers don't need to null-check the argument if the method returns `false`. To make a method like this nullable aware, you'd set the argument to a nullable reference type, and add the `NotNullWhen` attribute: + +```csharp +bool IsNullOrEmpty([NotNullWhen(false)]string? value); +``` + +That informs the compiler that any code where the return value is `false` need not be null-checked. The addition of the attribute informs the compiler's static analysis that `IsNullOrEmpty` performs the necessary null check: when it returns `false`, the input argument is not `null`. + +```csharp +string? userInput = GetUserInput(); +if (!string.IsNullOrEmpty(userInput)) +{ + int messageLength = userInput.Length; // no null check needed. +} +// null check needed on userInput here. +``` + +The method will be annotated as shown above for .NET Core 3.0. You may have similar methods in your codebase that check the state of objects for null values. The compiler won't recognize custom null check methods, and you'll need to add the annotations yourself. When you add the attribute, the compiler's static analysis knows when the tested variable has been null checked. + +Another use for these attributes is the `Try*` pattern. The postconditions for `ref` and `out` variables are communicated through the return value. Consider this method shown earlier: + +```csharp +bool TryGetMessage(string key, out string message) +``` + +The preceding method follows a typical .NET idiom: the return value indicates if `message` was set to the found value or, if no message is found, to the default value. If the method returns `true`, the value of `message` isn't null; otherwise, the method sets `message` to null. + +You can communicate that idiom using the `NotNullWhen` attribute. When you update the signature for nullable reference types, make `message` a `string?` and add an attribute: + +```csharp +bool TryGetMessage(string key, [NotNullWhen(true)] out string? message) +``` + +In the preceding example, the value of `message` is known to be not null when `TryGetMessage` returns `true`. You should annotate similar methods in your codebase in the same way: the arguments could be `null`, and are known to be not null when the method returns `true`. + +There's one final attribute you may also need. Sometimes the null state of a return value depends on the null state of one or more input arguments. These methods will return a non-null value whenever certain input arguments aren't `null`. To correctly annotate these methods, you use the `NotNullIfNotNull` attribute. Consider the following method: + +```csharp +string GetTopLevelDomainFromFullUrl(string url); +``` + +If the `url` argument isn't null, the output isn't `null`. Once nullable references are enabled, that signature works correctly, provided your API never accepts a null input. However, if the input could be null, then return value could also be null. Therefore, you could change the signature to the following code: + +```csharp +string? GetTopLevelDomainFromFullUrl(string? url); +``` + +That also works, but will often force callers to implement extra `null` checks. The contract is that the return value would be `null` only when the input argument `url` is `null`. To express that contract, you would annotate this method as shown in the following code: + +```csharp +[return: NotNullIfNotNull("url")] +string? GetTopLevelDomainFromFullUrl(string? url); +``` + +The return value and the argument have both been annotated with the `?` indicating that either could be `null`. The attribute further clarifies that the return value won't be null when the `url` argument isn't `null`. + +You specify conditional postconditions using these attributes: + +- [MaybeNullWhen](xref:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute): A non-nullable input argument may be null when the method returns the specified `bool` value. +- [NotNullWhen](xref:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute): A nullable input argument will not be null when the method returns the specified `bool` value. +- [NotNullIfNotNull](xref:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute): A return value isn't null if the input argument for the specified parameter isn't null. + +## Verify unreachable code + +Some methods, typically exception helpers or other utility methods, always exit by throwing an exception. Or, a helper may throw an exception based on the value of a Boolean argument. + +In the first case, you can add the `DoesNotReturn` attribute to the method declaration. The compiler helps you in three ways. First, the compiler issues a warning if there is a path where the method can exit without throwing an exception. Second, the compiler marks any code after a call to that method as *unreachable*, until an appropriate `catch` clause is encountered. Third, the unreachable code won't affect any null states. Consider this method: + +```csharp +[DoesNotReturn] +private void FailFast() +{ + throw new InvalidOperationException(); +} + +public void SetState(object containedField) +{ + if (!isInitialized) + FailFast(); + + // unreachable code: + this.field = containedField; +} +``` + +In the second case, you add the `DoesNotReturnIf` attribute to a Boolean parameter of the method. You can modify the previous example as follows: + +```csharp +private void FailFast([DoesNotReturnIf(false)]bool isValid) +{ + if (!isValid) + throw new InvalidOperationException(); +} + +public void SetState(object containedField) +{ + FailFast(isInitialized); + + // unreachable code when "isInitialized" is false: + this.field = containedField; +} +``` + +## Summary + +Adding nullable reference types provides an initial vocabulary to describe your APIs expectations for variables that could be `null`. The additional attributes provide a richer vocabulary to describe the null state of variables as preconditions and postconditions. These attributes more clearly describe your expectations and provide a better experience for the developers using your APIs. + +As you update libraries for a nullable context, add these attributes to guide users of your APIs to the correct usage. These attributes help you fully describe the null-state of input arguments and return values: + +- [AllowNull](xref:System.Diagnostics.CodeAnalysis.AllowNullAttribute): A non-nullable input argument may be null. +- [DisallowNull](xref:System.Diagnostics.CodeAnalysis.DisallowNullAttribute): A nullable input argument should never be null. +- [MaybeNull](xref:System.Diagnostics.CodeAnalysis.MaybeNullAttribute): A non-nullable return value may be null. +- [NotNull](xref:System.Diagnostics.CodeAnalysis.NotNullAttribute): A nullable return value will never be null. +- [MaybeNullWhen](xref:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute): A non-nullable input argument may be null when the method returns the specified `bool` value. +- [NotNullWhen](xref:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute): A nullable input argument will not be null when the method returns the specified `bool` value. +- [NotNullIfNotNull](xref:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute): A return value isn't null if the input argument for the specified parameter isn't null. +- [DoesNotReturn](xref:System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute): A method never returns. In other words, it always throws an exception. +- [DoesNotReturnIf](xref:System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute): This method never returns if the associated `bool` parameter has the specified value. diff --git a/docs/csharp/language-reference/attributes/snippets/ConditionalExamples.cs b/docs/csharp/language-reference/attributes/snippets/ConditionalExamples.cs new file mode 100644 index 0000000000000..6a1c62daf2273 --- /dev/null +++ b/docs/csharp/language-reference/attributes/snippets/ConditionalExamples.cs @@ -0,0 +1,46 @@ +using System; +using System.Diagnostics; + +namespace AttributeExamples +{ + public class Conditionals + { + // + [Conditional("DEBUG")] + static void DebugMethod() + { + } + // + + // + [Conditional("A"), Conditional("B")] + static void DoIfAorB() + { + // ... + } + // + } + + // + [Conditional("DEBUG")] + public class DocumentationAttribute : System.Attribute + { + string text; + + public DocumentationAttribute(string text) + { + this.text = text; + } + } + + class SampleClass + { + // This attribute will only be included if DEBUG is defined. + [Documentation("This method displays an integer.")] + static void DoWork(int i) + { + System.Console.WriteLine(i.ToString()); + } + } + // +} \ No newline at end of file diff --git a/samples/snippets/csharp/attributes/MultiUseAttribute.cs b/docs/csharp/language-reference/attributes/snippets/MultiUseAttribute.cs similarity index 66% rename from samples/snippets/csharp/attributes/MultiUseAttribute.cs rename to docs/csharp/language-reference/attributes/snippets/MultiUseAttribute.cs index e18a714b5b777..1fc2dae057f5b 100644 --- a/samples/snippets/csharp/attributes/MultiUseAttribute.cs +++ b/docs/csharp/language-reference/attributes/snippets/MultiUseAttribute.cs @@ -1,10 +1,8 @@ using System; -using System.Collections.Generic; -using System.Text; -namespace attributes +namespace AttributeExamples { - // + // [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] class MultiUse : Attribute { } @@ -14,5 +12,5 @@ class Class1 { } [MultiUse, MultiUse] class Class2 { } - // + // } diff --git a/docs/csharp/language-reference/attributes/snippets/NewAttribute.cs b/docs/csharp/language-reference/attributes/snippets/NewAttribute.cs new file mode 100644 index 0000000000000..75788ceac30b4 --- /dev/null +++ b/docs/csharp/language-reference/attributes/snippets/NewAttribute.cs @@ -0,0 +1,21 @@ +using System; + +namespace AttributeExamples +{ + namespace VersionOne + { + // + [AttributeUsage(AttributeTargets.All, + AllowMultiple = false, + Inherited = true)] + class NewAttribute : Attribute { } + // + } + namespace VersionTwo + { + // + [AttributeUsage(AttributeTargets.All)] + class NewAttribute : Attribute { } + // + } +} diff --git a/samples/snippets/csharp/attributes/NewPropertyOrFieldAttribute.cs b/docs/csharp/language-reference/attributes/snippets/NewPropertyOrFieldAttribute.cs similarity index 69% rename from samples/snippets/csharp/attributes/NewPropertyOrFieldAttribute.cs rename to docs/csharp/language-reference/attributes/snippets/NewPropertyOrFieldAttribute.cs index 45063de1cb42a..41ab7bf7d374a 100644 --- a/samples/snippets/csharp/attributes/NewPropertyOrFieldAttribute.cs +++ b/docs/csharp/language-reference/attributes/snippets/NewPropertyOrFieldAttribute.cs @@ -1,15 +1,13 @@ using System; -using System.Collections.Generic; -using System.Text; -namespace attributes +namespace AttributeExamples { - // + // [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] class NewPropertyOrFieldAttribute : Attribute { } - // + // - // + // class MyClass { // Attribute attached to property: @@ -20,5 +18,5 @@ class MyClass [field:NewPropertyOrField] public string Description { get; set; } } - // + // } diff --git a/samples/snippets/csharp/attributes/NonInheritedAttribute.cs b/docs/csharp/language-reference/attributes/snippets/NonInheritedAttribute.cs similarity index 71% rename from samples/snippets/csharp/attributes/NonInheritedAttribute.cs rename to docs/csharp/language-reference/attributes/snippets/NonInheritedAttribute.cs index 3baee16ceafda..5395ae4a8a704 100644 --- a/samples/snippets/csharp/attributes/NonInheritedAttribute.cs +++ b/docs/csharp/language-reference/attributes/snippets/NonInheritedAttribute.cs @@ -1,10 +1,8 @@ using System; -using System.Collections.Generic; -using System.Text; namespace attributes { - // + // [AttributeUsage(AttributeTargets.Class, Inherited = false)] class NonInheritedAttribute : Attribute { } @@ -12,5 +10,5 @@ class NonInheritedAttribute : Attribute { } class BClass { } class DClass : BClass { } - // + // } diff --git a/docs/csharp/language-reference/attributes/snippets/ObsoleteExample.cs b/docs/csharp/language-reference/attributes/snippets/ObsoleteExample.cs new file mode 100644 index 0000000000000..f34a32335cd41 --- /dev/null +++ b/docs/csharp/language-reference/attributes/snippets/ObsoleteExample.cs @@ -0,0 +1,35 @@ +using System; + +namespace AttributeExamples +{ + [Obsolete("use class B")] + public class A + { + public void Method() { } + } + + public class B + { + [Obsolete("use NewMethod", true)] + public void OldMethod() { } + + public void NewMethod() { } + } + + public static class ObsoleteProgram + { + public static void Main() + { + // Generates 2 warnings: + A a = new A(); + + // Generate no errors or warnings: + B b = new B(); + b.NewMethod(); + + // Generates an error, compilation fails. + // b.OldMethod(); + } + } +} + diff --git a/docs/csharp/language-reference/attributes/snippets/Program.cs b/docs/csharp/language-reference/attributes/snippets/Program.cs new file mode 100644 index 0000000000000..6e3457a22be27 --- /dev/null +++ b/docs/csharp/language-reference/attributes/snippets/Program.cs @@ -0,0 +1,13 @@ +using System; + +namespace AttributeExamples +{ + class Program + { + static void Main(string[] args) + { + TraceExample.Main(); + ObsoleteProgram.Main(); + } + } +} diff --git a/docs/csharp/language-reference/attributes/snippets/attributes.csproj b/docs/csharp/language-reference/attributes/snippets/attributes.csproj new file mode 100644 index 0000000000000..8e98a4686158a --- /dev/null +++ b/docs/csharp/language-reference/attributes/snippets/attributes.csproj @@ -0,0 +1,9 @@ + + + + Exe + netcoreapp3.1 + AttributeExamples.Program + + + diff --git a/docs/csharp/language-reference/attributes/snippets/trace.cs b/docs/csharp/language-reference/attributes/snippets/trace.cs new file mode 100644 index 0000000000000..64bf54f6f2ae9 --- /dev/null +++ b/docs/csharp/language-reference/attributes/snippets/trace.cs @@ -0,0 +1,24 @@ +#define TRACE_ON +using System; +using System.Diagnostics; + +namespace AttributeExamples +{ + public class Trace + { + [Conditional("TRACE_ON")] + public static void Msg(string msg) + { + Console.WriteLine(msg); + } + } + + public class TraceExample + { + public static void Main() + { + Trace.Msg("Now in Main..."); + Console.WriteLine("Done."); + } + } +} diff --git a/docs/csharp/language-reference/compiler-messages/cs0579.md b/docs/csharp/language-reference/compiler-messages/cs0579.md index 70240d2901ba2..30d8af88b506f 100644 --- a/docs/csharp/language-reference/compiler-messages/cs0579.md +++ b/docs/csharp/language-reference/compiler-messages/cs0579.md @@ -10,7 +10,7 @@ ms.assetid: 1a15af7e-60ad-4418-a493-15fdfe08e7db # Compiler Error CS0579 Duplicate 'attribute' attribute - It is not possible to specify the same attribute more than once unless the attribute specifies **AllowMultiple=true** in its [AttributeUsage](../../programming-guide/concepts/attributes/attributeusage.md). + It is not possible to specify the same attribute more than once unless the attribute specifies **AllowMultiple=true** in its [AttributeUsage](../../language-reference/attributes/general.md). ## Example The following example generates CS0579. diff --git a/docs/csharp/nullable-attributes.md b/docs/csharp/nullable-attributes.md index d497e311d3615..671e138d71819 100644 --- a/docs/csharp/nullable-attributes.md +++ b/docs/csharp/nullable-attributes.md @@ -75,205 +75,7 @@ However, for public libraries, or libraries with large user bases, you may prefe Several attributes have been added to express additional information about the null state of variables. All code you wrote before C# 8 introduced nullable reference types was *null oblivious*. That means any reference type variable may be null, but null checks aren't required. Once your code is *nullable aware*, those rules change. Reference types should never be the `null` value, and nullable reference types must be checked against `null` before being dereferenced. -The rules for your APIs are likely more complicated, as you saw with the `TryGetValue` API scenario. Many of your APIs have more complex rules for when variables can or can't be `null`. In these cases, you'll use one of the following attributes to express those rules: - -- [AllowNull](xref:System.Diagnostics.CodeAnalysis.AllowNullAttribute): A non-nullable input argument may be null. -- [DisallowNull](xref:System.Diagnostics.CodeAnalysis.DisallowNullAttribute): A nullable input argument should never be null. -- [MaybeNull](xref:System.Diagnostics.CodeAnalysis.MaybeNullAttribute): A non-nullable return value may be null. -- [NotNull](xref:System.Diagnostics.CodeAnalysis.NotNullAttribute): A nullable return value will never be null. -- [MaybeNullWhen](xref:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute): A non-nullable input argument may be null when the method returns the specified `bool` value. -- [NotNullWhen](xref:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute): A nullable input argument will not be null when the method returns the specified `bool` value. -- [NotNullIfNotNull](xref:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute): A return value isn't null if the argument for the specified parameter isn't null. - -The preceding descriptions are a quick reference to what each attribute does. Each following section describes the behavior and meaning more thoroughly. - -Adding these attributes gives the compiler more information about the rules for your API. When calling code is compiled in a nullable enabled context, the compiler will warn callers when they violate those rules. These attributes don't enable additional checks on your implementation. - -## Specify preconditions: `AllowNull` and `DisallowNull` - -Consider a read/write property that never returns `null` because it has a reasonable default value. Callers pass `null` to the set accessor when setting it to that default value. For example, consider a messaging system that asks for a screen name in a chat room. If none is provided, the system generates a random name: - -```csharp -public string ScreenName -{ - get => screenName; - set => screenName = value ?? GenerateRandomScreenName(); -} -private string screenName; -``` - -When you compile the preceding code in a nullable oblivious context, everything is fine. Once you enable nullable reference types, the `ScreenName` property becomes a non-nullable reference. That's correct for the `get` accessor: it never returns `null`. Callers don't need to check the returned property for `null`. But now setting the property to `null` generates a warning. In order to continue to support this type of code, you add the attribute to the property, as shown in the following code: - -```csharp -[AllowNull] -public string ScreenName -{ - get => screenName; - set => screenName = value ?? GenerateRandomScreenName(); -} -private string screenName = GenerateRandomScreenName(); -``` - -You may need to add a `using` directive for to use this and other attributes discussed in this article. The attribute is applied to the property, not the `set` accessor. The `AllowNull` attribute specifies *pre-conditions*, and only applies to inputs. The `get` accessor has a return value, but no input arguments. Therefore, the `AllowNull` attribute only applies to the `set` accessor. - -The preceding example demonstrates what to look for when adding the `AllowNull` attribute on an argument: - -1. The general contract for that variable is that it shouldn't be `null`, so you want a non-nullable reference type. -1. There are scenarios for the input variable to be `null`, though they aren't the most common usage. - -Most often you'll need this attribute for properties, or `in`, `out`, and `ref` arguments. The `AllowNull` attribute is the best choice when a variable is typically non-null, but you need to allow `null` as a precondition. - -Contrast that with scenarios for using `DisallowNull`: You use this attribute to specify that an input variable of a nullable reference type shouldn't be `null`. Consider a property where `null` is the default value, but clients can only set it to a non-null value. Consider the following code: - -```csharp -public string ReviewComment -{ - get => _comment; - set => _comment = value ?? throw new ArgumentNullException(nameof(value), "Cannot set to null"); -} -string _comment; -``` - -The preceding code is the best way to express your design that the `ReviewComment` could be `null`, but can't be set to `null`. Once this code is nullable aware, you can express this concept more clearly to callers using the : - -```csharp -[DisallowNull] -public string? ReviewComment -{ - get => _comment; - set => _comment = value ?? throw new ArgumentNullException(nameof(value), "Cannot set to null"); -} -string? _comment; -``` - -In a nullable context, the `ReviewComment` `get` accessor could return the default value of `null`. The compiler warns that it must be checked before access. Furthermore, it warns callers that, even though it could be `null`, callers shouldn't explicitly set it to `null`. The `DisallowNull` attribute also specifies a *pre-condition*, it does not affect the `get` accessor. You should choose to use the `DisallowNull` attribute when you observe these characteristics about: - -1. The variable could be `null` in core scenarios, often when first instantiated. -1. The variable shouldn't be explicitly set to `null`. - -These situations are common in code that was originally *null oblivious*. It may be that object properties are set in two distinct initialization operations. It may be that some properties are set only after some asynchronous work has completed. - -The `AllowNull` and `DisallowNull` attributes enable you to specify that preconditions on variables may not match the nullable annotations on those variables. These provide more detail about the characteristics of your API. This additional information helps callers use your API correctly. Remember you specify preconditions using the following attributes: - -- [AllowNull](xref:System.Diagnostics.CodeAnalysis.AllowNullAttribute): A non-nullable input argument may be null. -- [DisallowNull](xref:System.Diagnostics.CodeAnalysis.DisallowNullAttribute): A nullable input argument should never be null. - -## Specify post-conditions: `MaybeNull` and `NotNull` - -Suppose you have a method with the following signature: - -```csharp -public Customer FindCustomer(string lastName, string firstName) -``` - -You've likely written a method like this to return `null` when the name sought wasn't found. The `null` clearly indicates that the record wasn't found. In this example, you'd likely change the return type from `Customer` to `Customer?`. Declaring the return value as a nullable reference type specifies the intent of this API clearly. - -For reasons covered under [Generic definitions and nullability](#generic-definitions-and-nullability) that technique does not work with generic methods. You may have a generic method that follows a similar pattern: - -```csharp -public T Find(IEnumerable sequence, Func match) -``` - -You can't specify that the return value is `T?`. The method returns `null` when the sought item isn't found. Since you can't declare a `T?` return type, you add the `MaybeNull` annotation to the method return: - -```csharp -[return: MaybeNull] -public T Find(IEnumerable sequence, Func match) -``` - -The preceding code informs callers that the contract implies a non-nullable type, but the return value *may* actually be null. Use the `MaybeNull` attribute when your API should be a non-nullable type, typically a generic type parameter, but there may be instances where `null` would be returned. - -You can also specify that a return value or an `out` or `ref` argument isn't null even though the type is a nullable reference type. Consider a method that ensures an array is large enough to hold a number of elements. If the input argument doesn't have capacity, the routine would allocate a new array and copy all the existing elements into it. If the input argument is `null`, the routine would allocate new storage. If there's sufficient capacity, the routine does nothing: - -```csharp -public void EnsureCapacity(ref T[] storage, int size) -``` - -You could call this routine as follows: - -```csharp -// messages has the default value (null) when EnsureCapacity is called: -EnsureCapacity(ref messages, 10); -// messages is not null. -EnsureCapacity(messages, 50); -``` - -After enabling null reference types, you want to ensure that the preceding code compiles without warnings. When the method returns, the `storage` argument is guaranteed to be not null. However, it's acceptable to call `EnsureCapacity` with a null reference. You can make `storage` a nullable reference type, and add the `NotNull` post-condition to the parameter declaration: - -```csharp -public void EnsureCapacity([NotNull]ref T[]? storage, int size) -``` - -The preceding code expresses the existing contract very clearly: Callers can pass a variable with the `null` value, but the return value is guaranteed to never be null. The `NotNull` attribute is most useful for `ref` and `out` arguments where `null` may be passed as an argument, but that argument is guaranteed to be not null when the method returns. - -You specify unconditional postconditions using the following attributes: - -- [MaybeNull](xref:System.Diagnostics.CodeAnalysis.MaybeNullAttribute): A non-nullable return value may be null. -- [NotNull](xref:System.Diagnostics.CodeAnalysis.NotNullAttribute): A nullable return value will never be null. - -## Specify conditional post-conditions: `NotNullWhen`, `MaybeNullWhen`, and `NotNullIfNotNull` - -You're likely familiar with the `string` method . This method returns `true` when the argument is null or an empty string. It's a form of null-check: Callers don't need to null-check the argument if the method returns `false`. To make a method like this nullable aware, you'd set the argument to a nullable reference type, and add the `NotNullWhen` attribute: - -```csharp -bool IsNullOrEmpty([NotNullWhen(false)]string? value); -``` - -That informs the compiler that any code where the return value is `false` need not be null-checked. The addition of the attribute informs the compiler's static analysis that `IsNullOrEmpty` performs the necessary null check: when it returns `false`, the input argument is not `null`. - -```csharp -string? userInput = GetUserInput(); -if (!string.IsNullOrEmpty(userInput)) -{ - int messageLength = userInput.Length; // no null check needed. -} -// null check needed on userInput here. -``` - -The method will be annotated as shown above for .NET Core 3.0. You may have similar methods in your codebase that check the state of objects for null values. The compiler won't recognize custom null check methods, and you'll need to add the annotations yourself. When you add the attribute, the compiler's static analysis knows when the tested variable has been null checked. - -Another use for these attributes is the `Try*` pattern. The postconditions for `ref` and `out` variables are communicated through the return value. Consider this method shown earlier: - -```csharp -bool TryGetMessage(string key, out string message) -``` - -The preceding method follows a typical .NET idiom: the return value indicates if `message` was set to the found value or, if no message is found, to the default value. If the method returns `true`, the value of `message` isn't null; otherwise, the method sets `message` to null. - -You can communicate that idiom using the `NotNullWhen` attribute. When you update the signature for nullable reference types, make `message` a `string?` and add an attribute: - -```csharp -bool TryGetMessage(string key, [NotNullWhen(true)] out string? message) -``` - -In the preceding example, the value of `message` is known to be not null when `TryGetMessage` returns `true`. You should annotate similar methods in your codebase in the same way: the arguments could be `null`, and are known to be not null when the method returns `true`. - -There's one final attribute you may also need. Sometimes the null state of a return value depends on the null state of one or more input arguments. These methods will return a non-null value whenever certain input arguments aren't `null`. To correctly annotate these methods, you use the `NotNullIfNotNull` attribute. Consider the following method: - -```csharp -string GetTopLevelDomainFromFullUrl(string url); -``` - -If the `url` argument isn't null, the output isn't `null`. Once nullable references are enabled, that signature works correctly, provided your API never accepts a null input. However, if the input could be null, then return value could also be null. Therefore, you could change the signature to the following code: - -```csharp -string? GetTopLevelDomainFromFullUrl(string? url); -``` - -That also works, but will often force callers to implement extra `null` checks. The contract is that the return value would be `null` only when the input argument `url` is `null`. To express that contract, you would annotate this method as shown in the following code: - -```csharp -[return: NotNullIfNotNull("url")] -string? GetTopLevelDomainFromFullUrl(string? url); -``` - -The return value and the argument have both been annotated with the `?` indicating that either could be `null`. The attribute further clarifies that the return value won't be null when the `url` argument isn't `null`. - -You specify conditional postconditions using these attributes: - -- [MaybeNullWhen](xref:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute): A non-nullable input argument may be null when the method returns the specified `bool` value. -- [NotNullWhen](xref:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute): A nullable input argument will not be null when the method returns the specified `bool` value. -- [NotNullIfNotNull](xref:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute): A return value isn't null if the input argument for the specified parameter isn't null. +The rules for your APIs are likely more complicated, as you saw with the `TryGetValue` API scenario. Many of your APIs have more complex rules for when variables can or can't be `null`. In these cases, you'll use attributes to express those rules. The attributes that describe the semantics of your API are found in the article on [Attributes that impact nullable analysis](./language-reference/attributes/nullable-analysis.md). ## Generic definitions and nullability @@ -284,17 +86,3 @@ This doesn't mean you can't use a nullable type (either value type or reference What it does mean is that you can't use `T?` in a generic class or method declaration without constraints. For example, won't be changed to return `T?`. You can overcome this limitation by adding either the `struct` or `class` constraint. With either of those constraints, the compiler knows how to generate code for both `T` and `T?`. You may want to restrict the types used for a generic type argument to be non-nullable types. You can do that by adding the `notnull` constraint on that type argument. When that constraint is applied, the type argument must not be a nullable type. - -## Conclusions - -Adding nullable reference types provides an initial vocabulary to describe your APIs expectations for variables that could be `null`. The additional attributes provide a richer vocabulary to describe the null state of variables as preconditions and postconditions. These attributes more clearly describe your expectations and provide a better experience for the developers using your APIs. - -As you update libraries for a nullable context, add these attributes to guide users of your APIs to the correct usage. These attributes help you fully describe the null-state of input arguments and return values: - -- [AllowNull](xref:System.Diagnostics.CodeAnalysis.AllowNullAttribute): A non-nullable input argument may be null. -- [DisallowNull](xref:System.Diagnostics.CodeAnalysis.DisallowNullAttribute): A nullable input argument should never be null. -- [MaybeNull](xref:System.Diagnostics.CodeAnalysis.MaybeNullAttribute): A non-nullable return value may be null. -- [NotNull](xref:System.Diagnostics.CodeAnalysis.NotNullAttribute): A nullable return value will never be null. -- [MaybeNullWhen](xref:System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute): A non-nullable input argument may be null when the method returns the specified `bool` value. -- [NotNullWhen](xref:System.Diagnostics.CodeAnalysis.NotNullWhenAttribute): A nullable input argument will not be null when the method returns the specified `bool` value. -- [NotNullIfNotNull](xref:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute): A return value isn't null if the input argument for the specified parameter isn't null. diff --git a/docs/csharp/programming-guide/concepts/attributes/attributeusage.md b/docs/csharp/programming-guide/concepts/attributes/attributeusage.md deleted file mode 100644 index 58b214e84bb5a..0000000000000 --- a/docs/csharp/programming-guide/concepts/attributes/attributeusage.md +++ /dev/null @@ -1,85 +0,0 @@ ---- -title: "AttributeUsage (C#)" -ms.date: 04/25/2018 ---- -# AttributeUsage (C#) - -Determines how a custom attribute class can be used. is an attribute you apply to custom attribute definitions. The `AttributeUsage` attribute enables you to control: - -- Which program elements attribute may be applied to. Unless you restrict its usage, an attribute may be applied to any of the following program elements: - - assembly - - module - - field - - event - - method - - param - - property - - return - - type -- Whether an attribute can be applied to a single program element multiple times. -- Whether attributes are inherited by derived classes. - -The default settings look like the following example when applied explicitly: - -[!code-csharp[Define a new attribute](../../../../../samples/snippets/csharp/attributes/NewAttribute.cs#1)] - -In this example, the `NewAttribute` class can be applied to any supported program element. But it can be applied only once to each entity. The attribute is inherited by derived classes when applied to a base class. - -The and arguments are optional, so the following code has the same effect: - -[!code-csharp[Omit optional attributes](../../../../../samples/snippets/csharp/attributes/NewAttribute.cs#2)] - -The first argument must be one or more elements of the enumeration. Multiple target types can be linked together with the OR operator, like the following example shows: - -[!code-csharp[Create an attribute for fields or properties](../../../../../samples/snippets/csharp/attributes/NewPropertyOrFieldAttribute.cs#1)] - -Beginning in C# 7.3, attributes can be applied to either the property or the backing field for an auto-implemented property. The attribute applies to the property, unless you specify the `field` specifier on the attribute. Both are shown in the following example: - -[!code-csharp[Create an attribute for fields or properties](../../../../../samples/snippets/csharp/attributes/NewPropertyOrFieldAttribute.cs#2)] - -If the argument is `true`, then the resulting attribute can be applied more than once to a single entity, as shown in the following example: - -[!code-csharp[Create and use an attribute that can be applied multiple times](../../../../../samples/snippets/csharp/attributes/MultiUseAttribute.cs#1)] - -In this case, `MultiUseAttribute` can be applied repeatedly because `AllowMultiple` is set to `true`. Both formats shown for applying multiple attributes are valid. - -If is `false`, then the attribute isn't inherited by classes derived from an attributed class. For example: - -[!code-csharp[Create and use an attribute that can be applied multiple times](../../../../../samples/snippets/csharp/attributes/NonInheritedAttribute.cs#1)] - -In this case `NonInheritedAttribute` isn't applied to `DClass` via inheritance. - -## Remarks - -The `AttributeUsage` attribute is a single-use attribute--it can't be applied more than once to the same class. `AttributeUsage` is an alias for . - -For more information, see [Accessing Attributes by Using Reflection (C#)](accessing-attributes-by-using-reflection.md). - -## Example - -The following example demonstrates the effect of the and arguments to the attribute, and how the custom attributes applied to a class can be enumerated. - -[!code-csharp[Applying and querying attributes](../../../../../samples/snippets/csharp/attributes/Program.cs#1)] - -## Sample Output - -```text -Attributes on Base Class: -FirstAttribute -SecondAttribute -Attributes on Derived Class: -ThirdAttribute -ThirdAttribute -SecondAttribute -``` - -## See also - -- -- -- [C# Programming Guide](../..//index.md) -- [Attributes](../../../..//standard/attributes/index.md) -- [Reflection (C#)](../reflection.md) -- [Attributes](index.md) -- [Creating Custom Attributes (C#)](creating-custom-attributes.md) -- [Accessing Attributes by Using Reflection (C#)](accessing-attributes-by-using-reflection.md) diff --git a/docs/csharp/programming-guide/concepts/attributes/common-attributes.md b/docs/csharp/programming-guide/concepts/attributes/common-attributes.md deleted file mode 100644 index 50c169508e637..0000000000000 --- a/docs/csharp/programming-guide/concepts/attributes/common-attributes.md +++ /dev/null @@ -1,233 +0,0 @@ ---- -title: "Common Attributes (C#)" -ms.date: 07/20/2015 -ms.assetid: 785a0526-6c0e-4599-8c61-ccdc88dd9965 ---- -# Common Attributes (C#) -This topic describes the attributes that are most commonly used in C# programs. - -- [Global Attributes](#Global) - -- [Obsolete Attribute](#Obsolete) - -- [Conditional Attribute](#Conditional) - -- [Caller Info Attributes](#CallerInfo) - -## Global Attributes - Most attributes are applied to specific language elements such as classes or methods; however, some attributes are global—they apply to an entire assembly or module. For example, the attribute can be used to embed version information into an assembly, like this: - -```csharp -[assembly: AssemblyVersion("1.0.0.0")] -``` - - Global attributes appear in the source code after any top-level `using` directives and before any type, module, or namespace declarations. Global attributes can appear in multiple source files, but the files must be compiled in a single compilation pass. In C# projects, global attributes are put in the AssemblyInfo.cs file. - - Assembly attributes are values that provide information about an assembly. They fall into the following categories: - -- Assembly identity attributes - -- Informational attributes - -- Assembly manifest attributes - -### Assembly Identity Attributes - Three attributes (with a strong name, if applicable) determine the identity of an assembly: name, version, and culture. These attributes form the full name of the assembly and are required when you reference it in code. You can set an assembly's version and culture using attributes. However, the name value is set by the compiler, the Visual Studio IDE in the [Assembly Information Dialog Box](/visualstudio/ide/reference/assembly-information-dialog-box), or the Assembly Linker (Al.exe) when the assembly is created, based on the file that contains the assembly manifest. The attribute specifies whether multiple copies of the assembly can coexist. - - The following table shows the identity attributes. - -|Attribute|Purpose| -|---------------|-------------| -||Fully describes the identity of an assembly.| -||Specifies the version of an assembly.| -||Specifies which culture the assembly supports.| -||Specifies whether an assembly supports side-by-side execution on the same computer, in the same process, or in the same application domain.| - -### Informational Attributes - You can use informational attributes to provide additional company or product information for an assembly. The following table shows the informational attributes defined in the namespace. - -|Attribute|Purpose| -|---------------|-------------| -||Defines a custom attribute that specifies a product name for an assembly manifest.| -||Defines a custom attribute that specifies a trademark for an assembly manifest.| -||Defines a custom attribute that specifies an informational version for an assembly manifest.| -||Defines a custom attribute that specifies a company name for an assembly manifest.| -||Defines a custom attribute that specifies a copyright for an assembly manifest.| -||Instructs the compiler to use a specific version number for the Win32 file version resource.| -||Indicates whether the assembly is compliant with the Common Language Specification (CLS).| - -### Assembly Manifest Attributes - You can use assembly manifest attributes to provide information in the assembly manifest. This includes title, description, default alias, and configuration. The following table shows the assembly manifest attributes defined in the namespace. - -|Attribute|Purpose| -|---------------|-------------| -||Defines a custom attribute that specifies an assembly title for an assembly manifest.| -||Defines a custom attribute that specifies an assembly description for an assembly manifest.| -||Defines a custom attribute that specifies an assembly configuration (such as retail or debug) for an assembly manifest.| -||Defines a friendly default alias for an assembly manifest| - -## Obsolete Attribute - The `Obsolete` attribute marks a program entity as one that is no longer recommended for use. Each use of an entity marked obsolete will subsequently generate a warning or an error, depending on how the attribute is configured. For example: - -```csharp -[System.Obsolete("use class B")] -class A -{ - public void Method() { } -} -class B -{ - [System.Obsolete("use NewMethod", true)] - public void OldMethod() { } - public void NewMethod() { } -} -``` - - In this example the `Obsolete` attribute is applied to class `A` and to method `B.OldMethod`. Because the second argument of the attribute constructor applied to `B.OldMethod` is set to `true`, this method will cause a compiler error, whereas using class `A` will just produce a warning. Calling `B.NewMethod`, however, produces no warning or error. - - The string provided as the first argument to attribute constructor will be displayed as part of the warning or error. For example, when you use it with the previous definitions, the following code generates two warnings and one error: - -```csharp -// Generates 2 warnings: -// A a = new A(); - -// Generate no errors or warnings: -B b = new B(); -b.NewMethod(); - -// Generates an error, terminating compilation: -// b.OldMethod(); -``` - - Two warnings for class `A` are generated: one for the declaration of the class reference, and one for the class constructor. - - The `Obsolete` attribute can be used without arguments, but including an explanation of why the item is obsolete and what to use instead is recommended. - - The `Obsolete` attribute is a single-use attribute and can be applied to any entity that allows attributes. `Obsolete` is an alias for . - -## Conditional Attribute - The `Conditional` attribute makes the execution of a method dependent on a preprocessing identifier. The `Conditional` attribute is an alias for , and can be applied to a method or an attribute class. - - In this example, `Conditional` is applied to a method to enable or disable the display of program-specific diagnostic information: - -```csharp -#define TRACE_ON -using System; -using System.Diagnostics; - -public class Trace -{ - [Conditional("TRACE_ON")] - public static void Msg(string msg) - { - Console.WriteLine(msg); - } -} - -public class ProgramClass -{ - static void Main() - { - Trace.Msg("Now in Main..."); - Console.WriteLine("Done."); - } -} -``` - - If the `TRACE_ON` identifier is not defined, no trace output will be displayed. - - The `Conditional` attribute is often used with the `DEBUG` identifier to enable trace and logging features for debug builds but not in release builds, like this: - -```csharp -[Conditional("DEBUG")] -static void DebugMethod() -{ -} -``` - - When a method marked as conditional is called, the presence or absence of the specified preprocessing symbol determines whether the call is included or omitted. If the symbol is defined, the call is included; otherwise, the call is omitted. Using `Conditional` is a cleaner, more elegant, and less error-prone alternative to enclosing methods inside `#if…#endif` blocks, like this: - -```csharp -#if DEBUG - void ConditionalMethod() - { - } -#endif -``` - - A conditional method must be a method in a class or struct declaration and must not have a return value. - -### Using Multiple Identifiers - If a method has multiple `Conditional` attributes, a call to the method is included if at least one of the conditional symbols is defined (in other words, the symbols are logically linked together by using the OR operator). In this example, the presence of either `A` or `B` will result in a method call: - -```csharp -[Conditional("A"), Conditional("B")] -static void DoIfAorB() -{ - // ... -} -``` - - To achieve the effect of logically linking symbols by using the AND operator, you can define serial conditional methods. For example, the second method below will execute only if both `A` and `B` are defined: - -```csharp -[Conditional("A")] -static void DoIfA() -{ - DoIfAandB(); -} - -[Conditional("B")] -static void DoIfAandB() -{ - // Code to execute when both A and B are defined... -} -``` - -### Using Conditional with Attribute Classes - The `Conditional` attribute can also be applied to an attribute class definition. In this example, the custom attribute `Documentation` will only add information to the metadata if DEBUG is defined. - -```csharp -[Conditional("DEBUG")] -public class Documentation : System.Attribute -{ - string text; - - public Documentation(string text) - { - this.text = text; - } -} - -class SampleClass -{ - // This attribute will only be included if DEBUG is defined. - [Documentation("This method displays an integer.")] - static void DoWork(int i) - { - System.Console.WriteLine(i.ToString()); - } -} -``` - -## Caller Info Attributes - By using Caller Info attributes, you can obtain information about the caller to a method. You can obtain the file path of the source code, the line number in the source code, and the member name of the caller. - - To obtain member caller information, you use attributes that are applied to optional parameters. Each optional parameter specifies a default value. The following table lists the Caller Info attributes that are defined in the namespace: - -|Attribute|Description|Type| -|---|---|---| -||Full path of the source file that contains the caller. This is the path at compile time.|`String`| -||Line number in the source file from which the method is called.|`Integer`| -||Method name or property name of the caller. For more information, see [Caller Information (C#)](../caller-information.md).|`String`| - - For more information about the Caller Info attributes, see [Caller Information (C#)](../caller-information.md). - -## See also - -- -- -- [C# Programming Guide](../../index.md) -- [Attributes](../../../../standard/attributes/index.md) -- [Reflection (C#)](../reflection.md) -- [Accessing Attributes by Using Reflection (C#)](./accessing-attributes-by-using-reflection.md) diff --git a/docs/csharp/programming-guide/concepts/attributes/creating-custom-attributes.md b/docs/csharp/programming-guide/concepts/attributes/creating-custom-attributes.md index 2dd60570ce9a0..49bf75332389f 100644 --- a/docs/csharp/programming-guide/concepts/attributes/creating-custom-attributes.md +++ b/docs/csharp/programming-guide/concepts/attributes/creating-custom-attributes.md @@ -65,4 +65,4 @@ class SampleClass - [Reflection (C#)](../reflection.md) - [Attributes (C#)](./index.md) - [Accessing Attributes by Using Reflection (C#)](./accessing-attributes-by-using-reflection.md) -- [AttributeUsage (C#)](./attributeusage.md) +- [AttributeUsage (C#)](../../../language-reference/attributes/general.md) diff --git a/docs/csharp/programming-guide/concepts/attributes/index.md b/docs/csharp/programming-guide/concepts/attributes/index.md index 4869143b1e93e..0146504a9e7aa 100644 --- a/docs/csharp/programming-guide/concepts/attributes/index.md +++ b/docs/csharp/programming-guide/concepts/attributes/index.md @@ -89,7 +89,7 @@ The following example shows how to apply attributes to methods, method parameter [!code-csharp[Applying attributes to different code elements](../../../../../samples/snippets/csharp/attributes/AttributesOverview.cs#6)] > [!NOTE] -> Regardless of the targets on which `ValidatedContract` is defined to be valid, the `return` target has to be specified, even if `ValidatedContract` were defined to apply only to return values. In other words, the compiler will not use `AttributeUsage` information to resolve ambiguous attribute targets. For more information, see [AttributeUsage (C#)](attributeusage.md). +> Regardless of the targets on which `ValidatedContract` is defined to be valid, the `return` target has to be specified, even if `ValidatedContract` were defined to apply only to return values. In other words, the compiler will not use `AttributeUsage` information to resolve ambiguous attribute targets. For more information, see [AttributeUsage (C#)](../../../language-reference/attributes/general.md). ## Common uses for attributes @@ -115,7 +115,7 @@ For more information, see: - [Accessing Attributes by Using Reflection (C#)](accessing-attributes-by-using-reflection.md) - [How to create a C/C++ union by using attributes (C#)](how-to-create-a-c-cpp-union-by-using-attributes.md) - [Common Attributes (C#)](common-attributes.md) -- [Caller Information (C#)](../caller-information.md) +- [Caller Information (C#)](../../../language-reference/attributes/caller-information.md) ## See also diff --git a/docs/csharp/programming-guide/concepts/caller-information.md b/docs/csharp/programming-guide/concepts/caller-information.md deleted file mode 100644 index 73e2970abc921..0000000000000 --- a/docs/csharp/programming-guide/concepts/caller-information.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -title: "Caller Information (C#)" -ms.date: 07/20/2015 -ms.assetid: ffad3d24-2fb7-4641-9124-53b5bc91d339 ---- -# Caller Information (C#) - -By using Caller Info attributes, you can obtain information about the caller to a method. You can obtain file path of the source code, the line number in the source code, and the member name of the caller. This information is helpful for tracing, debugging, and creating diagnostic tools. - -To obtain this information, you use attributes that are applied to optional parameters, each of which has a default value. The following table lists the Caller Info attributes that are defined in the namespace: - -|Attribute|Description|Type| -|---|---|---| -||Full path of the source file that contains the caller. This is the file path at compile time.|`String`| -||Line number in the source file at which the method is called.|`Integer`| -||Method or property name of the caller. See [Member Names](#member-names) later in this topic.|`String`| - -## Example - -The following example shows how to use Caller Info attributes. On each call to the `TraceMessage` method, the caller information is substituted as arguments to the optional parameters. - -```csharp -public void DoProcessing() -{ - TraceMessage("Something happened."); -} - -public void TraceMessage(string message, - [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", - [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", - [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0) -{ - System.Diagnostics.Trace.WriteLine("message: " + message); - System.Diagnostics.Trace.WriteLine("member name: " + memberName); - System.Diagnostics.Trace.WriteLine("source file path: " + sourceFilePath); - System.Diagnostics.Trace.WriteLine("source line number: " + sourceLineNumber); -} - -// Sample Output: -// message: Something happened. -// member name: DoProcessing -// source file path: c:\Visual Studio Projects\CallerInfoCS\CallerInfoCS\Form1.cs -// source line number: 31 -``` - -## Remarks - -You must specify an explicit default value for each optional parameter. You can't apply Caller Info attributes to parameters that aren't specified as optional. - -The Caller Info attributes don't make a parameter optional. Instead, they affect the default value that's passed in when the argument is omitted. - -Caller Info values are emitted as literals into the Intermediate Language (IL) at compile time. Unlike the results of the property for exceptions, the results aren't affected by obfuscation. - -You can explicitly supply the optional arguments to control the caller information or to hide caller information. - -### Member names - -You can use the `CallerMemberName` attribute to avoid specifying the member name as a `String` argument to the called method. By using this technique, you avoid the problem that **Rename Refactoring** doesn't change the `String` values. This benefit is especially useful for the following tasks: - -- Using tracing and diagnostic routines. - -- Implementing the interface when binding data. This interface allows the property of an object to notify a bound control that the property has changed, so that the control can display the updated information. Without the `CallerMemberName` attribute, you must specify the property name as a literal. - -The following chart shows the member names that are returned when you use the `CallerMemberName` attribute. - -|Calls occurs within|Member name result| -|-|-| -|Method, property, or event|The name of the method, property, or event from which the call originated.| -|Constructor|The string ".ctor"| -|Static constructor|The string ".cctor"| -|Destructor|The string "Finalize"| -|User-defined operators or conversions|The generated name for the member, for example, "op_Addition".| -|Attribute constructor|The name of the method or property to which the attribute is applied. If the attribute is any element within a member (such as a parameter, a return value, or a generic type parameter), this result is the name of the member that's associated with that element.| -|No containing member (for example, assembly-level or attributes that are applied to types)|The default value of the optional parameter.| - -## See also - -- [Attributes (C#)](./attributes/index.md) -- [Common Attributes (C#)](./attributes/common-attributes.md) -- [Named and Optional Arguments](../classes-and-structs/named-and-optional-arguments.md) -- [Programming Concepts (C#)](./index.md) diff --git a/docs/csharp/programming-guide/concepts/index.md b/docs/csharp/programming-guide/concepts/index.md index 570d1e6eafbc0..f092d6294b558 100644 --- a/docs/csharp/programming-guide/concepts/index.md +++ b/docs/csharp/programming-guide/concepts/index.md @@ -13,7 +13,6 @@ This section explains programming concepts in the C# language. |[Assemblies in .NET](../../../standard/assembly/index.md)|Describes how to create and use assemblies.| |[Asynchronous Programming with async and await (C#)](./async/index.md)|Describes how to write asynchronous solutions by using the [async](../../language-reference/keywords/async.md) and [await](../../language-reference/operators/await.md) keywords in C#. Includes a walkthrough.| |[Attributes (C#)](./attributes/index.md)|Discusses how to provide additional information about programming elements such as types, fields, methods, and properties by using attributes.| -|[Caller Information (C#)](./caller-information.md)|Describes how to obtain information about the caller of a method. This information includes the file path and the line number of the source code and the member name of the caller.| |[Collections (C#)](./collections.md)|Describes some of the types of collections provided by the .NET Framework. Demonstrates how to use simple collections and collections of key/value pairs.| |[Covariance and Contravariance (C#)](./covariance-contravariance/index.md)|Shows how to enable implicit conversion of generic type parameters in interfaces and delegates.| |[Expression Trees (C#)](./expression-trees/index.md)|Explains how you can use expression trees to enable dynamic modification of executable code.| diff --git a/docs/csharp/toc.yml b/docs/csharp/toc.yml index d135e60b50f12..7a30ee502b8ad 100644 --- a/docs/csharp/toc.yml +++ b/docs/csharp/toc.yml @@ -119,7 +119,7 @@ href: programming-guide/types/index.md - name: Nullable reference types href: nullable-references.md - - name: Describe nullable APIs using attributes and constraints + - name: Update API signatures to nullable references href: nullable-attributes.md - name: Namespaces href: programming-guide/namespaces/index.md @@ -374,16 +374,10 @@ href: programming-guide/concepts/attributes/index.md - name: Creating Custom Attributes href: programming-guide/concepts/attributes/creating-custom-attributes.md - - name: AttributeUsage - href: programming-guide/concepts/attributes/attributeusage.md - name: Accessing Attributes by Using Reflection href: programming-guide/concepts/attributes/accessing-attributes-by-using-reflection.md - name: "How to create a C/C++ union by using attributes" href: programming-guide/concepts/attributes/how-to-create-a-c-cpp-union-by-using-attributes.md - - name: Common Attributes - href: programming-guide/concepts/attributes/common-attributes.md - - name: Caller information - href: programming-guide/concepts/caller-information.md - name: Collections href: programming-guide/concepts/collections.md - name: Covariance and contravariance @@ -1683,6 +1677,19 @@ href: language-reference/tokens/interpolated.md - name: "@ -- verbatim identifier" href: language-reference/tokens/verbatim.md + - name: Attributes read by the compiler + items: + - name: Global attributes + displayName: AssemblyName, AssemblyVersion, AssemblyCulture, AssemblyFlags, AssemblyProduct, AssemblyTrademark, AssemblyInformationalVersion, AssemblyCompany, AssemblyCopyright, AssemblyFileVersion, CLSCompliant, AssemblyTitle, AssemblyDescription, AssemblyConfiguration, AssemblyDefaultAlias + - name: General + displayName: Conditional, Obsolete, AttributeUsage + href: language-reference/attributes/general.md + - name: Caller information + displayName: CallerFilePath, CallerLineNumber, CallerMemberName + href: language-reference/attributes/caller-information.md + - name: Nullable static analysis + displayName: AllowNull, DisallowNull, MaybeNull, NotNull, MaybeNullWhen, NotNullWhen, NotNullIfNotNull, DoesNotReturn, DoesNotReturnIf + href: language-reference/attributes/nullable-analysis.md - name: C# preprocessor directives items: - name: Overview diff --git a/docs/csharp/whats-new/csharp-version-history.md b/docs/csharp/whats-new/csharp-version-history.md index c2a8b5c2503f6..fa6d7be811205 100644 --- a/docs/csharp/whats-new/csharp-version-history.md +++ b/docs/csharp/whats-new/csharp-version-history.md @@ -115,7 +115,7 @@ Dynamic binding gives you the potential for errors but also great power within t C# version 5.0, released with Visual Studio 2012, was a focused version of the language. Nearly all of the effort for that version went into another groundbreaking language concept: the `async` and `await` model for asynchronous programming. Here is the major features list: - [Asynchronous members](../async.md) -- [Caller info attributes](../programming-guide/concepts/caller-information.md) +- [Caller info attributes](../language-reference/attributes/caller-information.md) ### See Also diff --git a/docs/framework/winforms/controls/raise-change-notifications--bindingsource.md b/docs/framework/winforms/controls/raise-change-notifications--bindingsource.md index 8cb3fc7c59fc1..25610def7d600 100644 --- a/docs/framework/winforms/controls/raise-change-notifications--bindingsource.md +++ b/docs/framework/winforms/controls/raise-change-notifications--bindingsource.md @@ -23,7 +23,7 @@ The component will automatically detec ## Example The following code example demonstrates a simple implementation of the interface. It also shows how the automatically passes a data source change to a bound control when the is bound to a list of the type. - If you use the `CallerMemberName` attribute, calls to the `NotifyPropertyChanged` method don't have to specify the property name as a string argument. For more information, see [Caller Information (C#)](../../../csharp/programming-guide/concepts/caller-information.md) or [Caller Information (Visual Basic)](../../../visual-basic/programming-guide/concepts/caller-information.md). + If you use the `CallerMemberName` attribute, calls to the `NotifyPropertyChanged` method don't have to specify the property name as a string argument. For more information, see [Caller Information (C#)](../../../csharp/language-reference/attributes/caller-information.md) or [Caller Information (Visual Basic)](../../../visual-basic/programming-guide/concepts/caller-information.md). [!code-csharp[System.ComponentModel.IPropertyChangeExample#1](~/samples/snippets/csharp/VS_Snippets_Winforms/System.ComponentModel.IPropertyChangeExample/CS/Form1.cs#1)] [!code-vb[System.ComponentModel.IPropertyChangeExample#1](~/samples/snippets/visualbasic/VS_Snippets_Winforms/System.ComponentModel.IPropertyChangeExample/VB/Form1.vb#1)] diff --git a/samples/snippets/csharp/attributes/NewAttribute.cs b/samples/snippets/csharp/attributes/NewAttribute.cs deleted file mode 100644 index 5ed8080c31cd6..0000000000000 --- a/samples/snippets/csharp/attributes/NewAttribute.cs +++ /dev/null @@ -1,23 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace attributes -{ - namespace VersionOne - { - // - [System.AttributeUsage(System.AttributeTargets.All, - AllowMultiple = false, - Inherited = true)] - class NewAttribute : System.Attribute { } - // - } - namespace VersionTwo - { - // - [System.AttributeUsage(System.AttributeTargets.All)] - class NewAttribute : System.Attribute { } - // - } -} From 15741b714a2cfb8bc5c9fa2785b2a80b5ac0b59e Mon Sep 17 00:00:00 2001 From: furoTmark Date: Tue, 14 Apr 2020 19:59:41 +0300 Subject: [PATCH 04/14] Updated documentation with the path where xsd can be found (#17653) * Updated documentation with the path where xsd can be found * Fixed linter issues * Update docs/standard/serialization/xml-schema-def-tool-gen.md Co-Authored-By: Andy De George <2672110+Thraka@users.noreply.github.com> * Update xml-schema-def-tool-gen.md Co-authored-by: Andy De George <2672110+Thraka@users.noreply.github.com> --- docs/standard/serialization/xml-schema-def-tool-gen.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/standard/serialization/xml-schema-def-tool-gen.md b/docs/standard/serialization/xml-schema-def-tool-gen.md index aa2534ca05018..89e20e75f7570 100644 --- a/docs/standard/serialization/xml-schema-def-tool-gen.md +++ b/docs/standard/serialization/xml-schema-def-tool-gen.md @@ -9,8 +9,11 @@ helpviewer_keywords: ms.assetid: 51f0edc3-993d-4051-b7f2-77753694d3d1 --- # How to: Use the XML Schema Definition Tool to Generate Classes and XML Schema Documents -The XML Schema Definition tool (Xsd.exe) allows you to generate an XML schema that describes a class or to generate the class defined by an XML schema. The following procedures show how to perform these operations. - +The XML Schema Definition tool (Xsd.exe) allows you to generate an XML schema that describes a class or to generate the class defined by an XML schema. The following procedures show how to perform these operations. + +The XML Schema Definition tool (Xsd.exe) usually can be found in the following path:\ +_C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\{version}\\bin\\NETFX {version} Tools\\_ + ### To generate classes that conform to a specific schema 1. Open a command prompt. From c49459024ef8aa39c2bd8e5e196facaab1457de3 Mon Sep 17 00:00:00 2001 From: furoTmark Date: Tue, 14 Apr 2020 19:59:56 +0300 Subject: [PATCH 05/14] Updated documentation with the path where xsd can be found (#17654) * Updated documentation with the path where xsd can be found * Update docs/standard/serialization/xml-schema-definition-tool-xsd-exe.md Co-Authored-By: Andy De George <2672110+Thraka@users.noreply.github.com> Co-authored-by: Andy De George <2672110+Thraka@users.noreply.github.com> --- .../serialization/xml-schema-definition-tool-xsd-exe.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/standard/serialization/xml-schema-definition-tool-xsd-exe.md b/docs/standard/serialization/xml-schema-definition-tool-xsd-exe.md index c218cf690b0a8..683e1cd7d0066 100644 --- a/docs/standard/serialization/xml-schema-definition-tool-xsd-exe.md +++ b/docs/standard/serialization/xml-schema-definition-tool-xsd-exe.md @@ -7,6 +7,9 @@ ms.assetid: a6e6e65c-347f-4494-9457-653bf29baac2 The XML Schema Definition (Xsd.exe) tool generates XML schema or common language runtime classes from XDR, XML, and XSD files, or from classes in a runtime assembly. +The XML Schema Definition tool (Xsd.exe) usually can be found in the following path:\ +_C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\{version}\\bin\\NETFX {version} Tools\\_ + ## Syntax Run the tool from the command line. From 8ad4ca2a2773eb66fa772cec351f19619a86727a Mon Sep 17 00:00:00 2001 From: Tom Dykstra Date: Tue, 14 Apr 2020 11:05:00 -0700 Subject: [PATCH 06/14] Fix typo (#17841) --- docs/core/tools/dotnet-tool-restore.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/tools/dotnet-tool-restore.md b/docs/core/tools/dotnet-tool-restore.md index c0eb7d8356259..a79ae53967830 100644 --- a/docs/core/tools/dotnet-tool-restore.md +++ b/docs/core/tools/dotnet-tool-restore.md @@ -17,7 +17,7 @@ ms.date: 02/14/2020 dotnet tool restore [--configfile] [--add-source] [tool-manifest] [--disable-parallel] [--ignore-failed-sources] - [--no-cache] [-interactive] [-v|--verbosity] + [--no-cache] [--interactive] [-v|--verbosity] dotnet tool restore <-h|--help> ``` From 5ffae250aaa53d5eb25e7dffdd32ba08ff3a0427 Mon Sep 17 00:00:00 2001 From: Jeroen Oortwijn <51476918+JeroenOortwijn@users.noreply.github.com> Date: Tue, 14 Apr 2020 21:05:12 +0200 Subject: [PATCH 07/14] Updated line number references (#17835) The line-referencing has an off-by-one error. --- docs/framework/wpf/advanced/attached-properties-overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/framework/wpf/advanced/attached-properties-overview.md b/docs/framework/wpf/advanced/attached-properties-overview.md index 3b933853a8623..4bff479093cfa 100644 --- a/docs/framework/wpf/advanced/attached-properties-overview.md +++ b/docs/framework/wpf/advanced/attached-properties-overview.md @@ -61,7 +61,7 @@ The following example shows how you can set an attached property in code. In thi [!code-csharp[PropertiesOvwSupport#APCode](~/samples/snippets/csharp/VS_Snippets_Wpf/PropertiesOvwSupport/CSharp/page4.xaml.cs#apcode)] [!code-vb[PropertiesOvwSupport#APCode](~/samples/snippets/visualbasic/VS_Snippets_Wpf/PropertiesOvwSupport/visualbasic/page4.xaml.vb#apcode)] -Similar to the XAML case, if `myCheckBox` had not already been added as a child element of `myDockPanel` by the third line of code, the fourth line of code would not raise an exception, but the property value would not interact with a parent and thus would do nothing. Only a value set on a child element combined with the presence of a parent element will cause an effective behavior in the rendered application. (In this case, you could set the attached property, then attach to the tree. Or you could attach to the tree then set the attached property. Either action order provides the same result.) +Similar to the XAML case, if `myCheckBox` had not already been added as a child element of `myDockPanel` by the fourth line of code, the fifth line of code would not raise an exception, but the property value would not interact with a parent and thus would do nothing. Only a value set on a child element combined with the presence of a parent element will cause an effective behavior in the rendered application. (In this case, you could set the attached property, then attach to the tree. Or you could attach to the tree then set the attached property. Either action order provides the same result.) ## Attached Property Metadata From dd75b7eb4328f7634854b828cc172ffea0861dee Mon Sep 17 00:00:00 2001 From: Genevieve Warren Date: Tue, 14 Apr 2020 13:05:05 -0700 Subject: [PATCH 08/14] Update add web reference instructions (#17831) * update add web reference instructions --- .../consuming-a-dataset-from-an-xml-web-service.md | 11 +++++++---- ...g-ws-i-basic-profile-1-1-interoperable-services.md | 6 +++--- .../config-wcf-service-with-aspnet-web-service.md | 7 ++++--- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/docs/framework/data/adonet/dataset-datatable-dataview/consuming-a-dataset-from-an-xml-web-service.md b/docs/framework/data/adonet/dataset-datatable-dataview/consuming-a-dataset-from-an-xml-web-service.md index 2dfd9b9e2f68d..6dee77395816a 100644 --- a/docs/framework/data/adonet/dataset-datatable-dataview/consuming-a-dataset-from-an-xml-web-service.md +++ b/docs/framework/data/adonet/dataset-datatable-dataview/consuming-a-dataset-from-an-xml-web-service.md @@ -6,7 +6,8 @@ dev_langs: - "vb" ms.assetid: 9edd6b71-0fa5-4649-ae1d-ac1c12541019 --- -# Consuming a DataSet from an XML Web Service +# Consume a DataSet from an XML web service + The was architected with a disconnected design, in part to facilitate the convenient transport of data over the Internet. The **DataSet** is "serializable" in that it can be specified as an input to or output from XML Web services without any additional coding required to stream the contents of the **DataSet** from an XML Web service to a client and back. The **DataSet** is implicitly converted to an XML stream using the DiffGram format, sent over the network, and then reconstructed from the XML stream as a **DataSet** on the receiving end. This gives you a very simple and flexible method for transmitting and returning relational data using XML Web services. For more information about the DiffGram format, see [DiffGrams](diffgrams.md). The following example shows how to create an XML Web service and client that use the **DataSet** to transport relational data (including modified data) and resolve any updates back to the original data source. @@ -14,7 +15,7 @@ The was architected with a disconnected design, in pa > [!NOTE] > We recommend that you always consider security implications when creating an XML Web service. For information on securing an XML Web service, see [Securing XML Web Services Created Using ASP.NET](https://docs.microsoft.com/previous-versions/dotnet/netframework-4.0/w67h0dw7(v=vs.100)). -### To create an XML Web service that returns and consumes a DataSet +## Create an XML web service 1. Create the XML Web service. @@ -183,9 +184,11 @@ The was architected with a disconnected design, in pa 3. Create an XML Web service client. - If you want to have Visual Studio generate the Web service proxy class for you, simply create the client project, and, in the Solution Explorer window, right-click the project, click **Add Web Reference**, and select the Web service from the list of available Web services (this may require supplying the address of the Web service endpoint, if the Web service isn't available within the current solution, or on the current computer.) If you create the XML Web service proxy yourself (as described in the previous step), you can import it into your client code and consume the XML Web service methods. The following sample code imports the proxy library, calls **GetCustomers** to get a list of customers, adds a new customer, and then returns a **DataSet** with the updates to **UpdateCustomers**. + If you want to have Visual Studio generate the Web service proxy class for you, simply create the client project, and, in the Solution Explorer window, right-click the project, and then select **Add** > **Service Reference**. In the **Add Service Reference** dialog box, select **Advanced**, and then select **Add Web Reference**. Select the Web service from the list of available Web services (this may require supplying the address of the Web service endpoint if the Web service isn't available within the current solution or on the current computer). If you create the XML Web service proxy yourself (as described in the previous step), you can import it into your client code and consume the XML Web service methods. + + The following sample code imports the proxy library, calls **GetCustomers** to get a list of customers, adds a new customer, and then returns a **DataSet** with the updates to **UpdateCustomers**. - Notice that the example passes the **DataSet** returned by **DataSet.GetChanges** to **UpdateCustomers** because only modified rows need to be passed to **UpdateCustomers**. **UpdateCustomers** returns the resolved **DataSet**, which you can then **Merge** into the existing **DataSet** to incorporate the resolved changes and any row error information from the update. The following code assumes that you have used Visual Studio to create the Web reference, and that you have renamed the Web reference to DsSample in the **Add Web Reference** dialog box. + The example passes the **DataSet** returned by **DataSet.GetChanges** to **UpdateCustomers** because only modified rows need to be passed to **UpdateCustomers**. **UpdateCustomers** returns the resolved **DataSet**, which you can then **Merge** into the existing **DataSet** to incorporate the resolved changes and any row error information from the update. The following code assumes that you have used Visual Studio to create the Web reference, and that you have renamed the Web reference to DsSample in the **Add Web Reference** dialog box. ```vb Imports System diff --git a/docs/framework/wcf/creating-ws-i-basic-profile-1-1-interoperable-services.md b/docs/framework/wcf/creating-ws-i-basic-profile-1-1-interoperable-services.md index eaae29db2c2b2..215a9115989b7 100644 --- a/docs/framework/wcf/creating-ws-i-basic-profile-1-1-interoperable-services.md +++ b/docs/framework/wcf/creating-ws-i-basic-profile-1-1-interoperable-services.md @@ -15,15 +15,15 @@ To configure a WCF service endpoint to be interoperable with ASP.NET Web service - Do not use callback and session contract features or transaction behaviors on your service endpoint - You can optionally enable support for HTTPS and transport-level client authentication on the binding. +You can optionally enable support for HTTPS and transport-level client authentication on the binding. - The following features of the class require functionality beyond WS-I Basic Profile 1.1: +The following features of the class require functionality beyond WS-I Basic Profile 1.1: - Message Transmission Optimization Mechanism (MTOM) message encoding controlled by the property. Leave this property at its default value, which is to not use MTOM. - Message security controlled by the value provides WS-Security support compliant with WS-I Basic Security Profile 1.0. Leave this property at its default value, which is to not use WS-Security. - To make the metadata for a WCF service available to ASP.NET, use the Web service client generation tools: [Web Services Description Language Tool (Wsdl.exe)](https://docs.microsoft.com/previous-versions/dotnet/netframework-4.0/7h3ystb6%28v=vs.100%29), [Web Services Discovery Tool (Disco.exe)](https://docs.microsoft.com/previous-versions/dotnet/netframework-4.0/cy2a3ybs%28v=vs.100%29), and the `Add Web Reference` feature in Visual Studio; you must enable metadata publication. For more information, see [Publishing Metadata Endpoints](publishing-metadata-endpoints.md). +To make the metadata for a WCF service available to ASP.NET, use the Web service client generation tools: [Web Services Description Language Tool (Wsdl.exe)](https://docs.microsoft.com/previous-versions/dotnet/netframework-4.0/7h3ystb6%28v=vs.100%29), [Web Services Discovery Tool (Disco.exe)](https://docs.microsoft.com/previous-versions/dotnet/netframework-4.0/cy2a3ybs%28v=vs.100%29), and the **Add Web Reference** feature in Visual Studio. Enable metadata publication. For more information, see [Publishing Metadata Endpoints](publishing-metadata-endpoints.md). ## Example diff --git a/docs/framework/wcf/feature-details/config-wcf-service-with-aspnet-web-service.md b/docs/framework/wcf/feature-details/config-wcf-service-with-aspnet-web-service.md index 30bd9e0f74a8c..5c85462743753 100644 --- a/docs/framework/wcf/feature-details/config-wcf-service-with-aspnet-web-service.md +++ b/docs/framework/wcf/feature-details/config-wcf-service-with-aspnet-web-service.md @@ -7,13 +7,14 @@ dev_langs: ms.assetid: 48e1cd90-de80-4d6c-846e-631878955762 --- # How to: Configure WCF Service to Interoperate with ASP.NET Web Service Clients + To configure a Windows Communication Foundation (WCF) service endpoint to be interoperable with ASP.NET Web service clients, use the type as the binding type for your service endpoint. You can optionally enable support for HTTPS and transport-level client authentication on the binding. ASP.NET Web service clients do not support MTOM message encoding, so the property should be left as its default value, which is . ASP.Net Web Service clients do not support WS-Security, so the should be set to . - To make the metadata for a WCF service available to ASP.NET Web service proxy generation tools (that is, [Web Services Description Language Tool (Wsdl.exe)](https://docs.microsoft.com/previous-versions/dotnet/netframework-4.0/7h3ystb6(v%3dvs.100)), [Web Services Discovery Tool (Disco.exe)](https://docs.microsoft.com/previous-versions/dotnet/netframework-4.0/cy2a3ybs(v=vs.100)), and the Add Web Reference feature in Visual Studio), you should expose an HTTP/GET metadata endpoint. + To make the metadata for a WCF service available to ASP.NET Web service proxy generation tools (that is, [Web Services Description Language Tool (Wsdl.exe)](https://docs.microsoft.com/previous-versions/dotnet/netframework-4.0/7h3ystb6(v%3dvs.100)), [Web Services Discovery Tool (Disco.exe)](https://docs.microsoft.com/previous-versions/dotnet/netframework-4.0/cy2a3ybs(v=vs.100)), and the **Add Web Reference** feature in Visual Studio), you should expose an HTTP/GET metadata endpoint. -### To add a WCF endpoint that is compatible with ASP.NET Web service clients in code +## Add an endpoint in code 1. Create a new instance @@ -23,7 +24,7 @@ To configure a Windows Communication Foundation (WCF) service endpoint to be int 4. Enable an HTTP/GET metadata endpoint for your service. For details see [How to: Publish Metadata for a Service Using Code](../../../../docs/framework/wcf/feature-details/how-to-publish-metadata-for-a-service-using-code.md). -### To add a WCF endpoint that is compatible with ASP.NET Web service clients in a configuration file +## Add an endpoint in a configuration file 1. Create a new binding configuration. For details, see the [How to: Specify a Service Binding in Configuration](../../../../docs/framework/wcf/how-to-specify-a-service-binding-in-configuration.md). From 9af119bb056433e7a6966f38b9bdca1cc5a563c1 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 14 Apr 2020 17:42:58 -0400 Subject: [PATCH 09/14] Add async stream return types (#17843) * Add IAsyncEnumerable Fixes #16634 This commit: Add that `IAsyncEnumerable` is a valid return type for an async method. Add a new project and sample code for IAsyncEnumerable. * grammar cleanup In this commit, fix style issues and remove unused anchors. (Those anchors were added during migration). * move sample files This commit moves the old snippet files without any changes. * this commit migrates the samples The existing sample code was in the /samples folder. This commit moves those into the ./snippets folder, and adapts the includes to use the (new) preferred syntax. * fix typo * Apply suggestions from code review Co-Authored-By: Tom Dykstra * respond to additional feedback. Co-authored-by: Tom Dykstra --- .../concepts/async/async-return-types.md | 55 ++++++++++--------- .../async/snippets/AsyncExamples.csproj | 10 ++++ .../concepts/async/snippets/AsyncStreams.cs | 42 ++++++++++++++ .../concepts/async/snippets/Program.cs | 17 ++++++ .../concepts/async/snippets/async-returns1.cs | 34 ++++++++++++ .../async/snippets/async-returns1a.cs | 34 ++++++++++++ .../concepts/async/snippets/async-returns2.cs | 29 ++++++++++ .../async/snippets/async-returns2a.cs | 32 +++++++++++ .../async/snippets}/async-returns3.cs | 12 ++-- .../async/snippets}/async-valuetask.cs | 2 +- .../programming-guide/async/async-returns1.cs | 38 ------------- .../async/async-returns1a.cs | 44 --------------- .../programming-guide/async/async-returns2.cs | 32 ----------- .../async/async-returns2a.cs | 37 ------------- 14 files changed, 235 insertions(+), 183 deletions(-) create mode 100644 docs/csharp/programming-guide/concepts/async/snippets/AsyncExamples.csproj create mode 100644 docs/csharp/programming-guide/concepts/async/snippets/AsyncStreams.cs create mode 100644 docs/csharp/programming-guide/concepts/async/snippets/Program.cs create mode 100644 docs/csharp/programming-guide/concepts/async/snippets/async-returns1.cs create mode 100644 docs/csharp/programming-guide/concepts/async/snippets/async-returns1a.cs create mode 100644 docs/csharp/programming-guide/concepts/async/snippets/async-returns2.cs create mode 100644 docs/csharp/programming-guide/concepts/async/snippets/async-returns2a.cs rename {samples/snippets/csharp/programming-guide/async => docs/csharp/programming-guide/concepts/async/snippets}/async-returns3.cs (82%) rename {samples/snippets/csharp/programming-guide/async => docs/csharp/programming-guide/concepts/async/snippets}/async-valuetask.cs (96%) delete mode 100644 samples/snippets/csharp/programming-guide/async/async-returns1.cs delete mode 100644 samples/snippets/csharp/programming-guide/async/async-returns1a.cs delete mode 100644 samples/snippets/csharp/programming-guide/async/async-returns2.cs delete mode 100644 samples/snippets/csharp/programming-guide/async/async-returns2a.cs diff --git a/docs/csharp/programming-guide/concepts/async/async-return-types.md b/docs/csharp/programming-guide/concepts/async/async-return-types.md index 6f35208d7accb..cedabc56f1b77 100644 --- a/docs/csharp/programming-guide/concepts/async/async-return-types.md +++ b/docs/csharp/programming-guide/concepts/async/async-return-types.md @@ -1,65 +1,62 @@ --- title: "Async Return Types (C#)" -ms.date: 05/29/2017 +ms.date: 04/14/2020 ms.assetid: ddb2539c-c898-48c1-ad92-245e4a996df8 --- # Async Return Types (C#) + Async methods can have the following return types: - , for an async method that returns a value. - - , for an async method that performs an operation but returns no value. - - `void`, for an event handler. - - Starting with C# 7.0, any type that has an accessible `GetAwaiter` method. The object returned by the `GetAwaiter` method must implement the interface. - +- Starting with C# 8.0, , for an async method that returns an *async stream*. + For more information about async methods, see [Asynchronous Programming with async and await (C#)](./index.md). -Each return type is examined in one of the following sections, and you can find a full example that uses all three types at the end of the topic. - -## Task\ Return Type -The return type is used for an async method that contains a [return](../../../language-reference/keywords/return.md) (C#) statement in which the operand has type `TResult`. +## Task\ Return Type +The return type is used for an async method that contains a [return](../../../language-reference/keywords/return.md) (C#) statement in which the operand is `TResult`. In the following example, the `GetLeisureHours` async method contains a `return` statement that returns an integer. Therefore, the method declaration must specify a return type of `Task`. The async method is a placeholder for an operation that returns a string. -[!code-csharp[return-value](../../../../../samples/snippets/csharp/programming-guide/async/async-returns1.cs)] +:::code language="csharp" source="./snippets/async-returns1.cs" id="SnippetFirstExample"::: When `GetLeisureHours` is called from within an await expression in the `ShowTodaysInfo` method, the await expression retrieves the integer value (the value of `leisureHours`) that's stored in the task returned by the `GetLeisureHours` method. For more information about await expressions, see [await](../../../language-reference/operators/await.md). -You can better understand how this happens by separating the call to `GetLeisureHours` from the application of `await`, as the following code shows. A call to method `GetLeisureHours` that isn't immediately awaited returns a `Task`, as you would expect from the declaration of the method. The task is assigned to the `integerTask` variable in the example. Because `integerTask` is a , it contains a property of type `TResult`. In this case, `TResult` represents an integer type. When `await` is applied to `integerTask`, the await expression evaluates to the contents of the property of `integerTask`. The value is assigned to the `ret` variable. +You can better understand how `await` retrieves the result from a `Task` by separating the call to `GetLeisureHours` from the application of `await`, as the following code shows. A call to method `GetLeisureHours` that isn't immediately awaited returns a `Task`, as you would expect from the declaration of the method. The task is assigned to the `integerTask` variable in the example. Because `integerTask` is a , it contains a property of type `TResult`. In this case, `TResult` represents an integer type. When `await` is applied to `integerTask`, the await expression evaluates to the contents of the property of `integerTask`. The value is assigned to the `ret` variable. > [!IMPORTANT] > The property is a blocking property. If you try to access it before its task is finished, the thread that's currently active is blocked until the task completes and the value is available. In most cases, you should access the value by using `await` instead of accessing the property directly.
The previous example retrieved the value of the property to block the main thread so that the `ShowTodaysInfo` method could finish execution before the application ended. -[!code-csharp[return-value](../../../../../samples/snippets/csharp/programming-guide/async/async-returns1a.cs#1)] - -## Task Return Type +:::code language="csharp" source="./snippets/async-returns1a.cs" id="SnippetSecondVersion"::: + +## Task Return Type Async methods that don't contain a `return` statement or that contain a `return` statement that doesn't return an operand usually have a return type of . Such methods return `void` if they run synchronously. If you use a return type for an async method, a calling method can use an `await` operator to suspend the caller's completion until the called async method has finished. -In the following example, the `WaitAndApologize` async method doesn't contain a `return` statement, so the method returns a object. This enables `WaitAndApologize` to be awaited. Note that the type doesn't include a `Result` property because it has no return value. +In the following example, the `WaitAndApologize` async method doesn't contain a `return` statement, so the method returns a object. Returning a `Task` enables `WaitAndApologize` to be awaited. The type doesn't include a `Result` property because it has no return value. + +:::code language="csharp" source="./snippets/async-returns2.cs" id="SnippetTaskReturn"::: -[!code-csharp[return-value](../../../../../samples/snippets/csharp/programming-guide/async/async-returns2.cs)] - `WaitAndApologize` is awaited by using an await statement instead of an await expression, similar to the calling statement for a synchronous void-returning method. The application of an await operator in this case doesn't produce a value. As in the previous example, you can separate the call to `WaitAndApologize` from the application of an await operator, as the following code shows. However, remember that a `Task` doesn't have a `Result` property, and that no value is produced when an await operator is applied to a `Task`. The following code separates calling the `WaitAndApologize` method from awaiting the task that the method returns. -[!code-csharp[return-value](../../../../../samples/snippets/csharp/programming-guide/async/async-returns2a.cs#1)] +:::code language="csharp" source="./snippets/async-returns2a.cs" id="SnippetAwaitTask"::: -## Void return type +## Void return type -You use the `void` return type in asynchronous event handlers, which require a `void` return type. For methods other than event handlers that don't return a value, you should return a instead, because an async method that returns `void` can't be awaited. Any caller of such a method must be able to continue to completion without waiting for the called async method to finish, and the caller must be independent of any values or exceptions that the async method generates. +You use the `void` return type in asynchronous event handlers, which require a `void` return type. For methods other than event handlers that don't return a value, you should return a instead, because an async method that returns `void` can't be awaited. Any caller of such a method must continue to completion without waiting for the called async method to finish. The caller must be independent of any values or exceptions that the async method generates. -The caller of a void-returning async method can't catch exceptions that are thrown from the method, and such unhandled exceptions are likely to cause your application to fail. If an exception occurs in an async method that returns a or , the exception is stored in the returned task and is rethrown when the task is awaited. Therefore, make sure that any async method that can produce an exception has a return type of or and that calls to the method are awaited. +The caller of a void-returning async method can't catch exceptions thrown from the method, and such unhandled exceptions are likely to cause your application to fail. If a method that returns a or throws an exception, the exception is stored in the returned task. The exception is rethrown when the task is awaited. Therefore, make sure that any async method that can produce an exception has a return type of or and that calls to the method are awaited. -For more information about how to catch exceptions in async methods, see the [Exceptions in Async Methods](../../../language-reference/keywords/try-catch.md#exceptions-in-async-methods) section of the [try-catch](../../../language-reference/keywords/try-catch.md) topic. +For more information about how to catch exceptions in async methods, see the [Exceptions in Async Methods](../../../language-reference/keywords/try-catch.md#exceptions-in-async-methods) section of the [try-catch](../../../language-reference/keywords/try-catch.md) article. -The following example shows the behavior of an async event handler. Note that in the example code, an async event handler must let the main thread know when it finishes. Then the main thread can wait for an async event handler to complete before exiting the program. +The following example shows the behavior of an async event handler. In the example code, an async event handler must let the main thread know when it finishes. Then the main thread can wait for an async event handler to complete before exiting the program. -[!code-csharp[return-value](../../../../../samples/snippets/csharp/programming-guide/async/async-returns3.cs)] +:::code language="csharp" source="./snippets/async-returns3.cs"::: ## Generalized async return types and ValueTask\ @@ -69,7 +66,15 @@ Because and structure as a lightweight implementation of a generalized task-returning value. To use the type, you must add the `System.Threading.Tasks.Extensions` NuGet package to your project. The following example uses the structure to retrieve the value of two dice rolls. -[!code-csharp[return-value](../../../../../samples/snippets/csharp/programming-guide/async/async-valuetask.cs)] +:::code language="csharp" source="./snippets/async-valuetask.cs"::: + +## Async streams with IAsyncEnumerable\ + +Starting with C# 8.0, an async method may return an *async stream*, represented by . An async stream provides a way to enumerate items read from a stream when elements are generated in chunks with repeated asynchronous calls. The following example shows an async method that generates an async stream: + +:::code language="csharp" source="./snippets/AsyncStreams.cs" id="SnippetGenerateAsyncStream"::: + +The preceding example reads lines from a string asynchronously. Once each line is read, the code enumerates each word in the string. Callers would enumerate each word using the `await foreach` statement. The method awaits when it needs to asynchronously read the next line from the source string. ## See also diff --git a/docs/csharp/programming-guide/concepts/async/snippets/AsyncExamples.csproj b/docs/csharp/programming-guide/concepts/async/snippets/AsyncExamples.csproj new file mode 100644 index 0000000000000..d1a45393188c1 --- /dev/null +++ b/docs/csharp/programming-guide/concepts/async/snippets/AsyncExamples.csproj @@ -0,0 +1,10 @@ + + + + Exe + netcoreapp3.1 + Enable + AsyncExamples.Program + + + diff --git a/docs/csharp/programming-guide/concepts/async/snippets/AsyncStreams.cs b/docs/csharp/programming-guide/concepts/async/snippets/AsyncStreams.cs new file mode 100644 index 0000000000000..911544d0496aa --- /dev/null +++ b/docs/csharp/programming-guide/concepts/async/snippets/AsyncStreams.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace AsyncExamples +{ + + public static class AsyncStreamExample + { + + public static async Task Examples() + { + await foreach (var word in ReadWordsFromStream()) + Console.WriteLine(word); + } + + // + private static async IAsyncEnumerable ReadWordsFromStream() + { + string data = + @"This is a line of text. + Here is the second line of text. + And there is one more for good measure. + Wait, that was the penultimate line."; + + using var readStream = new StringReader(data); + + string? line = await readStream.ReadLineAsync(); + while (line != null) + { + var words = line.Split(' ',StringSplitOptions.RemoveEmptyEntries); + foreach (var word in words) + { + yield return word; + } + line = await readStream.ReadLineAsync(); + } + } + // + } +} \ No newline at end of file diff --git a/docs/csharp/programming-guide/concepts/async/snippets/Program.cs b/docs/csharp/programming-guide/concepts/async/snippets/Program.cs new file mode 100644 index 0000000000000..176fbc164081c --- /dev/null +++ b/docs/csharp/programming-guide/concepts/async/snippets/Program.cs @@ -0,0 +1,17 @@ +using System.Threading.Tasks; + +namespace AsyncExamples +{ + public static class Program + { + static async Task Main() + { + await FirstExample.ShowTodaysInfo(); + await SecondExample.ShowTodaysInfo(); + await ExampleTask.DisplayCurrentInfo(); + await AwaitTaskExample.DisplayCurrentInfo(); + await AsyncVoidExample.Main(); + await AsyncStreamExample.Examples(); + } + } +} diff --git a/docs/csharp/programming-guide/concepts/async/snippets/async-returns1.cs b/docs/csharp/programming-guide/concepts/async/snippets/async-returns1.cs new file mode 100644 index 0000000000000..14b25ee018cd0 --- /dev/null +++ b/docs/csharp/programming-guide/concepts/async/snippets/async-returns1.cs @@ -0,0 +1,34 @@ +using System; +using System.Linq; +using System.Threading.Tasks; + +public class FirstExample +{ + // + public static async Task ShowTodaysInfo() + { + string ret = $"Today is {DateTime.Today:D}\n" + + "Today's hours of leisure: " + + $"{await GetLeisureHours()}"; + return ret; + } + + static async Task GetLeisureHours() + { + // Task.FromResult is a placeholder for actual work that returns a string. + var today = await Task.FromResult(DateTime.Now.DayOfWeek.ToString()); + + // The method then can process the result in some way. + int leisureHours; + if (today.First() == 'S') + leisureHours = 16; + else + leisureHours = 5; + + return leisureHours; + } + // The example displays output like the following: + // Today is Wednesday, May 24, 2017 + // Today's hours of leisure: 5 + // +} diff --git a/docs/csharp/programming-guide/concepts/async/snippets/async-returns1a.cs b/docs/csharp/programming-guide/concepts/async/snippets/async-returns1a.cs new file mode 100644 index 0000000000000..34e035efc747b --- /dev/null +++ b/docs/csharp/programming-guide/concepts/async/snippets/async-returns1a.cs @@ -0,0 +1,34 @@ +using System; +using System.Linq; +using System.Threading.Tasks; + +public class SecondExample +{ + public static async Task ShowTodaysInfo() + { + // + var integerTask = GetLeisureHours(); + + // You can do other work that does not rely on integerTask before awaiting. + string ret = $"Today is {DateTime.Today:D}\n" + + "Today's hours of leisure: " + + $"{await integerTask}"; + return ret; + // + } + + static async Task GetLeisureHours() + { + // Task.FromResult is a placeholder for actual work that returns a string. + var today = await Task.FromResult(DateTime.Now.DayOfWeek.ToString()); + + // The method then can process the result in some way. + int leisureHours; + if (today.First() == 'S') + leisureHours = 16; + else + leisureHours = 5; + + return leisureHours; + } +} diff --git a/docs/csharp/programming-guide/concepts/async/snippets/async-returns2.cs b/docs/csharp/programming-guide/concepts/async/snippets/async-returns2.cs new file mode 100644 index 0000000000000..2fa493a2cc9ca --- /dev/null +++ b/docs/csharp/programming-guide/concepts/async/snippets/async-returns2.cs @@ -0,0 +1,29 @@ +using System; +using System.Threading.Tasks; + +public class ExampleTask +{ + // + public static async Task DisplayCurrentInfo() + { + await WaitAndApologize(); + Console.WriteLine($"Today is {DateTime.Now:D}"); + Console.WriteLine($"The current time is {DateTime.Now.TimeOfDay:t}"); + Console.WriteLine("The current temperature is 76 degrees."); + } + + static async Task WaitAndApologize() + { + // Task.Delay is a placeholder for actual work. + await Task.Delay(2000); + // Task.Delay delays the following line by two seconds. + Console.WriteLine("\nSorry for the delay. . . .\n"); + } + // The example displays the following output: + // Sorry for the delay. . . . + // + // Today is Wednesday, May 24, 2017 + // The current time is 15:25:16.2935649 + // The current temperature is 76 degrees. + // +} diff --git a/docs/csharp/programming-guide/concepts/async/snippets/async-returns2a.cs b/docs/csharp/programming-guide/concepts/async/snippets/async-returns2a.cs new file mode 100644 index 0000000000000..5a13169d886b9 --- /dev/null +++ b/docs/csharp/programming-guide/concepts/async/snippets/async-returns2a.cs @@ -0,0 +1,32 @@ +using System; +using System.Threading.Tasks; + +public class AwaitTaskExample +{ + public static async Task DisplayCurrentInfo() + { + // + Task wait = WaitAndApologize(); + + string output = $"Today is {DateTime.Now:D}\n" + + $"The current time is {DateTime.Now.TimeOfDay:t}\n" + + $"The current temperature is 76 degrees.\n"; + await wait; + Console.WriteLine(output); + // + } + + static async Task WaitAndApologize() + { + // Task.Delay is a placeholder for actual work. + await Task.Delay(2000); + // Task.Delay delays the following line by two seconds. + Console.WriteLine("\nSorry for the delay. . . .\n"); + } +} +// The example displays the following output: +// Sorry for the delay. . . . +// +// Today is Wednesday, May 24, 2017 +// The current time is 15:25:16.2935649 +// The current temperature is 76 degrees. diff --git a/samples/snippets/csharp/programming-guide/async/async-returns3.cs b/docs/csharp/programming-guide/concepts/async/snippets/async-returns3.cs similarity index 82% rename from samples/snippets/csharp/programming-guide/async/async-returns3.cs rename to docs/csharp/programming-guide/concepts/async/snippets/async-returns3.cs index 277df9331cc53..f83db3f27cac7 100644 --- a/samples/snippets/csharp/programming-guide/async/async-returns3.cs +++ b/docs/csharp/programming-guide/concepts/async/snippets/async-returns3.cs @@ -3,7 +3,7 @@ public class NaiveButton { - public event EventHandler Clicked; + public event EventHandler? Clicked; public void Click() { @@ -15,9 +15,9 @@ public void Click() public class AsyncVoidExample { - static TaskCompletionSource tcs; + static TaskCompletionSource tcs = new TaskCompletionSource(); - static async Task Main() + public static async Task Main() { tcs = new TaskCompletionSource(); var secondHandlerFinished = tcs.Task; @@ -34,14 +34,14 @@ static async Task Main() await secondHandlerFinished; } - private static void Button_Clicked_1(object sender, EventArgs e) + private static void Button_Clicked_1(object? sender, EventArgs e) { Console.WriteLine(" Handler 1 is starting..."); Task.Delay(100).Wait(); Console.WriteLine(" Handler 1 is done."); } - private static async void Button_Clicked_2_Async(object sender, EventArgs e) + private static async void Button_Clicked_2_Async(object? sender, EventArgs e) { Console.WriteLine(" Handler 2 is starting..."); Task.Delay(100).Wait(); @@ -51,7 +51,7 @@ private static async void Button_Clicked_2_Async(object sender, EventArgs e) tcs.SetResult(true); } - private static void Button_Clicked_3(object sender, EventArgs e) + private static void Button_Clicked_3(object? sender, EventArgs e) { Console.WriteLine(" Handler 3 is starting..."); Task.Delay(100).Wait(); diff --git a/samples/snippets/csharp/programming-guide/async/async-valuetask.cs b/docs/csharp/programming-guide/concepts/async/snippets/async-valuetask.cs similarity index 96% rename from samples/snippets/csharp/programming-guide/async/async-valuetask.cs rename to docs/csharp/programming-guide/concepts/async/snippets/async-valuetask.cs index 96a042b8ea623..33799dae4a29d 100644 --- a/samples/snippets/csharp/programming-guide/async/async-valuetask.cs +++ b/docs/csharp/programming-guide/concepts/async/snippets/async-valuetask.cs @@ -3,7 +3,7 @@ class Program { - static Random rnd; + static Random? rnd; static void Main() { diff --git a/samples/snippets/csharp/programming-guide/async/async-returns1.cs b/samples/snippets/csharp/programming-guide/async/async-returns1.cs deleted file mode 100644 index ace54f3c9e28a..0000000000000 --- a/samples/snippets/csharp/programming-guide/async/async-returns1.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; - -public class Example -{ - public static void Main() - { - Console.WriteLine(ShowTodaysInfo().Result); - } - - private static async Task ShowTodaysInfo() - { - string ret = $"Today is {DateTime.Today:D}\n" + - "Today's hours of leisure: " + - $"{await GetLeisureHours()}"; - return ret; - } - - static async Task GetLeisureHours() - { - // Task.FromResult is a placeholder for actual work that returns a string. - var today = await Task.FromResult(DateTime.Now.DayOfWeek.ToString()); - - // The method then can process the result in some way. - int leisureHours; - if (today.First() == 'S') - leisureHours = 16; - else - leisureHours = 5; - - return leisureHours; - } -} -// The example displays output like the following: -// Today is Wednesday, May 24, 2017 -// Today's hours of leisure: 5 -// diff --git a/samples/snippets/csharp/programming-guide/async/async-returns1a.cs b/samples/snippets/csharp/programming-guide/async/async-returns1a.cs deleted file mode 100644 index 5f701c8f557ed..0000000000000 --- a/samples/snippets/csharp/programming-guide/async/async-returns1a.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System; -using System.Linq; -using System.Threading.Tasks; - -public class Example -{ - public static void Main() - { - Console.WriteLine(ShowTodaysInfo().Result); - } - - private static async Task ShowTodaysInfo() - { - // - var integerTask = GetLeisureHours(); - - // You can do other work that does not rely on integerTask before awaiting. - - string ret = $"Today is {DateTime.Today:D}\n" + - "Today's hours of leisure: " + - $"{await integerTask}"; - // - return ret; - } - - static async Task GetLeisureHours() - { - // Task.FromResult is a placeholder for actual work that returns a string. - var today = await Task.FromResult(DateTime.Now.DayOfWeek.ToString()); - - // The method then can process the result in some way. - int leisureHours; - if (today.First() == 'S') - leisureHours = 16; - else - leisureHours = 5; - - return leisureHours; - } -} -// The example displays output like the following: -// Today is Wednesday, May 24, 2017 -// Today's hours of leisure: 5 -// diff --git a/samples/snippets/csharp/programming-guide/async/async-returns2.cs b/samples/snippets/csharp/programming-guide/async/async-returns2.cs deleted file mode 100644 index a3ad3166706c9..0000000000000 --- a/samples/snippets/csharp/programming-guide/async/async-returns2.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System; -using System.Threading.Tasks; - -public class Example -{ - public static void Main() - { - DisplayCurrentInfo().Wait(); - } - - static async Task DisplayCurrentInfo() - { - await WaitAndApologize(); - Console.WriteLine($"Today is {DateTime.Now:D}"); - Console.WriteLine($"The current time is {DateTime.Now.TimeOfDay:t}"); - Console.WriteLine("The current temperature is 76 degrees."); - } - - static async Task WaitAndApologize() - { - // Task.Delay is a placeholder for actual work. - await Task.Delay(2000); - // Task.Delay delays the following line by two seconds. - Console.WriteLine("\nSorry for the delay. . . .\n"); - } -} -// The example displays the following output: -// Sorry for the delay. . . . -// -// Today is Wednesday, May 24, 2017 -// The current time is 15:25:16.2935649 -// The current temperature is 76 degrees. diff --git a/samples/snippets/csharp/programming-guide/async/async-returns2a.cs b/samples/snippets/csharp/programming-guide/async/async-returns2a.cs deleted file mode 100644 index 4e67429bf843a..0000000000000 --- a/samples/snippets/csharp/programming-guide/async/async-returns2a.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Threading.Tasks; - -public class Example -{ - public static void Main() - { - DisplayCurrentInfo().Wait(); - } - - static async Task DisplayCurrentInfo() - { - // - Task wait = WaitAndApologize(); - - string output = $"Today is {DateTime.Now:D}\n" + - $"The current time is {DateTime.Now.TimeOfDay:t}\n" + - $"The current temperature is 76 degrees.\n"; - await wait; - Console.WriteLine(output); - // - } - - static async Task WaitAndApologize() - { - // Task.Delay is a placeholder for actual work. - await Task.Delay(2000); - // Task.Delay delays the following line by two seconds. - Console.WriteLine("\nSorry for the delay. . . .\n"); - } -} -// The example displays the following output: -// Sorry for the delay. . . . -// -// Today is Wednesday, May 24, 2017 -// The current time is 15:25:16.2935649 -// The current temperature is 76 degrees. From c5a92f0832df7862a1541a66e4c1cbb2598cc954 Mon Sep 17 00:00:00 2001 From: sguitardude Date: Tue, 14 Apr 2020 16:43:29 -0500 Subject: [PATCH 10/14] Remove redundant words: in Visual Studio (#17842) --- .../concepts/linq/introduction-to-linq-queries.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/csharp/programming-guide/concepts/linq/introduction-to-linq-queries.md b/docs/csharp/programming-guide/concepts/linq/introduction-to-linq-queries.md index b12c785863c52..f84a1484bc770 100644 --- a/docs/csharp/programming-guide/concepts/linq/introduction-to-linq-queries.md +++ b/docs/csharp/programming-guide/concepts/linq/introduction-to-linq-queries.md @@ -35,7 +35,7 @@ A *query* is an expression that retrieves data from a data source. Queries are u [!code-csharp[CsLINQGettingStarted#2](~/samples/snippets/csharp/VS_Snippets_VBCSharp/CsLINQGettingStarted/CS/Class1.cs#2)] - With [!INCLUDE[vbtecdlinq](~/includes/vbtecdlinq-md.md)], you first create an object-relational mapping at design time either manually or by using the [LINQ to SQL Tools in Visual Studio](/visualstudio/data-tools/linq-to-sql-tools-in-visual-studio2) in Visual Studio. You write your queries against the objects, and at run-time [!INCLUDE[vbtecdlinq](~/includes/vbtecdlinq-md.md)] handles the communication with the database. In the following example, `Customers` represents a specific table in the database, and the type of the query result, , derives from . + With [!INCLUDE[vbtecdlinq](~/includes/vbtecdlinq-md.md)], you first create an object-relational mapping at design time either manually or by using the [LINQ to SQL Tools in Visual Studio](/visualstudio/data-tools/linq-to-sql-tools-in-visual-studio2). You write your queries against the objects, and at run-time [!INCLUDE[vbtecdlinq](~/includes/vbtecdlinq-md.md)] handles the communication with the database. In the following example, `Customers` represents a specific table in the database, and the type of the query result, , derives from . ```csharp Northwnd db = new Northwnd(@"c:\northwnd.mdf"); From 21ddf898c709e4234ecd947cce47965b252cf2cf Mon Sep 17 00:00:00 2001 From: Levi Rocha Date: Tue, 14 Apr 2020 17:53:58 -0400 Subject: [PATCH 11/14] Fix typos (#17741) --- .../docker-app-development-workflow.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/architecture/microservices/docker-application-development-process/docker-app-development-workflow.md b/docs/architecture/microservices/docker-application-development-process/docker-app-development-workflow.md index 33893705367e3..b8d38fb3398ef 100644 --- a/docs/architecture/microservices/docker-application-development-process/docker-app-development-workflow.md +++ b/docs/architecture/microservices/docker-application-development-process/docker-app-development-workflow.md @@ -280,7 +280,7 @@ The resulting file is then: 7 COPY . . 8 RUN dotnet restore /ignoreprojectextensions:.dcproj 9 WORKDIR /src/src/Services/Catalog/Catalog.API -10 RUN dotnet publish Catalog.API.csproj -c Release -0 /app +10 RUN dotnet publish Catalog.API.csproj -c Release -o /app 11 12 FROM base AS final 13 WORKDIR /app @@ -473,7 +473,7 @@ After the docker-compose up command runs, the application and its related contai #### Using Visual Studio -Running a multi-container application using Visual Studio 2019 can't get any simpler. You just press **Ctrl-F5** to run or **F5** to debug, as usual, setting up the **docker-compose** project as the startup project. Visual Studio handles all needed setup, so you can create breakpoints as usual and debug what finally become independent processes running in "remote servers", with the debugger already attached. just like that. +Running a multi-container application using Visual Studio 2019 can't get any simpler. You just press **Ctrl-F5** to run or **F5** to debug, as usual, setting up the **docker-compose** project as the startup project. Visual Studio handles all needed setup, so you can create breakpoints as usual and debug what finally become independent processes running in "remote servers", with the debugger already attached, just like that. As mentioned before, each time you add Docker solution support to a project within a solution, that project is configured in the global (solution-level) docker-compose.yml file, which lets you run or debug the whole solution at once. Visual Studio will start one container for each project that has Docker solution support enabled, and perform all the internal steps for you (dotnet publish, docker build, etc.). From d811b1ba72096e5e847f63ac10cf0ed310c91609 Mon Sep 17 00:00:00 2001 From: Bill Wagner Date: Tue, 14 Apr 2020 18:27:43 -0400 Subject: [PATCH 12/14] remove extra spaces (#17847) In my previous edit, several of the label names had an extra space. This PR removes them. --- .ghal.rules.json | 66 ++++++++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/.ghal.rules.json b/.ghal.rules.json index 87ec86729953b..e07d5c05df6e2 100644 --- a/.ghal.rules.json +++ b/.ghal.rules.json @@ -239,100 +239,100 @@ "labels-add": ":card_file_box: Technology - C# / VB diagnostics" }, "(?i).*docs\/csharp\/whats-new.*": { - "labels-add": ":card_file_box: Technology - C# What's New" + "labels-add": ":card_file_box: Technology - C# What's New" }, "(?i).*docs\/csharp\/how-to.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/linq.*": { - "labels-add": ":card_file_box: Technology - LINQ" + "labels-add": ":card_file_box: Technology - LINQ" }, "(?i).*docs\/csharp\/programming-guide\/main-and-command-args.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/programming-guide\/indexers.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/programming-guide\/generics.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/programming-guide\/strings.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/programming-guide\/types.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/programming-guide\/statements-expressions-operators.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/programming-guide\/interop.*": { - "labels-add": ":card_file_box: Technology - C# Advanced concepts" + "labels-add": ":card_file_box: Technology - C# Advanced concepts" }, "(?i).*docs\/csharp\/programming-guide\/unsafe-code-pointers.*": { - "labels-add": ":card_file_box: Technology - C# Advanced concepts" + "labels-add": ":card_file_box: Technology - C# Advanced concepts" }, "(?i).*docs\/csharp\/programming-guide\/exceptions.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/programming-guide\/namespaces.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/programming-guide\/nullable-types.*": { - "labels-add": ":card_file_box: Technology - C# Null safety" + "labels-add": ":card_file_box: Technology - C# Null safety" }, "(?i).*docs\/csharp\/programming-guide\/arrays.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/programming-guide\/concepts\/covariance-contravariance.*": { - "labels-add": ":card_file_box: Technology - C# Advanced concepts" + "labels-add": ":card_file_box: Technology - C# Advanced concepts" }, "(?i).*docs\/csharp\/programming-guide\/concepts\/serialization.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/programming-guide\/concepts\/expression-trees.*": { - "labels-add": ":card_file_box: Technology - C# Advanced concepts" + "labels-add": ":card_file_box: Technology - C# Advanced concepts" }, "(?i).*docs\/csharp\/programming-guide\/concepts\/async.*": { - "labels-add": ":card_file_box: Technology - Async Task" + "labels-add": ":card_file_box: Technology - Async Task" }, "(?i).*docs\/csharp\/programming-guide\/concepts\/linq.*": { - "labels-add": ":card_file_box: Technology - LINQ" + "labels-add": ":card_file_box: Technology - LINQ" }, "(?i).*docs\/csharp\/programming-guide\/concepts\/attributes.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/programming-guide\/xmldoc.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/programming-guide\/classes-and-structs.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/programming-guide\/delegates.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/programming-guide\/file-system.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/programming-guide\/events.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/programming-guide\/inside-a-program.*": { - "labels-add": ":card_file_box: Technology - C# Get Started" + "labels-add": ":card_file_box: Technology - C# Get Started" }, "(?i).*docs\/csharp\/programming-guide\/interfaces.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/getting-started.*": { - "labels-add": ":card_file_box: Technology - C# Get Started" + "labels-add": ":card_file_box: Technology - C# Get Started" }, "(?i).*docs\/csharp\/tutorials\/exploration.*": { - "labels-add": ":card_file_box: Technology - C# Get Started" + "labels-add": ":card_file_box: Technology - C# Get Started" }, "(?i).*docs\/csharp\/tutorial\/intro-to-csharp.*": { - "labels-add": ":card_file_box: Technology - C# Get Started" + "labels-add": ":card_file_box: Technology - C# Get Started" }, "(?i).*docs\/csharp\/tutorials.*": { - "labels-add": ":card_file_box: Technology - C# Fundamentals" + "labels-add": ":card_file_box: Technology - C# Fundamentals" }, "(?i).*docs\/csharp\/language-reference\/compiler-messages.*": { "labels-add": ":card_file_box: Technology - C# / VB diagnostics" @@ -344,7 +344,7 @@ "labels-add": ":card_file_box: Technology - Roslyn APIs" }, "(?i).*docs\/csharp\/tour-of-csharp.*": { - "labels-add": ":card_file_box: Technology - C# Get Started" + "labels-add": ":card_file_box: Technology - C# Get Started" }, "(?i).*docs\/desktop-wpf*": { "labels-add": ":books: Area - Desktop Guide,:card_file_box: Technology - WPF" From 6f72b51a1305466b566b08a76c3aebaf76962c8b Mon Sep 17 00:00:00 2001 From: Brice Lambson Date: Tue, 14 Apr 2020 17:08:54 -0700 Subject: [PATCH 13/14] Microsoft.Data.Sqlite: Add uint to data types table (#17848) Fixes #17784 --- docs/standard/data/sqlite/types.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/standard/data/sqlite/types.md b/docs/standard/data/sqlite/types.md index e970518c80dc7..17bbbf4a488e5 100644 --- a/docs/standard/data/sqlite/types.md +++ b/docs/standard/data/sqlite/types.md @@ -26,6 +26,7 @@ SQLite only has four primitive data types: INTEGER, REAL, TEXT, and BLOB. APIs t | String | TEXT | UTF-8 | | TimeSpan | TEXT | d.hh:mm:ss.fffffff | | UInt16 | INTEGER | | +| UInt32 | INTEGER | | | UInt64 | INTEGER | Large values overflow | ## Alternative types From af6bdcd63994e6fce9f6c0118ee1fa966c4c3528 Mon Sep 17 00:00:00 2001 From: Genevieve Warren Date: Tue, 14 Apr 2020 17:18:09 -0700 Subject: [PATCH 14/14] Fixes #17826 (#17829) --- docs/core/project-sdk/overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/project-sdk/overview.md b/docs/core/project-sdk/overview.md index a8857e972c499..ddca21a5b0bc8 100644 --- a/docs/core/project-sdk/overview.md +++ b/docs/core/project-sdk/overview.md @@ -6,7 +6,7 @@ ms.topic: conceptual --- # .NET Core project SDKs -.NET Core projects are associated with a software development kit (SDK). Each project SDK is a set of MSBuild [targets](/visualstudio/msbuild/msbuild-targets) and associated [tasks](/visualstudio/msbuild/msbuild-tasks) that are responsible for compiling, packing, and publishing code. +.NET Core projects are associated with a software development kit (SDK). Each *project SDK* is a set of MSBuild [targets](/visualstudio/msbuild/msbuild-targets) and associated [tasks](/visualstudio/msbuild/msbuild-tasks) that are responsible for compiling, packing, and publishing code. A project that references a project SDK is sometimes referred to as an *SDK-style project*. ## Available SDKs