diff --git a/docs/visual-basic/programming-guide/language-features/data-types/generic-types.md b/docs/visual-basic/programming-guide/language-features/data-types/generic-types.md index 5da15590b0db7..a7b626d0e9c74 100644 --- a/docs/visual-basic/programming-guide/language-features/data-types/generic-types.md +++ b/docs/visual-basic/programming-guide/language-features/data-types/generic-types.md @@ -1,7 +1,7 @@ --- description: "Learn more about: Generic Types in Visual Basic (Visual Basic)" title: "Generic Types" -ms.date: 07/20/2015 +ms.date: 01/31/2025 helpviewer_keywords: - "generic interfaces" - "data type arguments [Visual Basic], defining" @@ -36,120 +36,107 @@ helpviewer_keywords: - "data type parameters [Visual Basic], defining" - "type arguments [Visual Basic], defining" - "arguments [Visual Basic], type" -ms.assetid: 89f771d9-ecbb-4737-88b8-116b63c6cf4d --- -# Generic Types in Visual Basic (Visual Basic) - -A *generic type* is a single programming element that adapts to perform the same functionality for a variety of data types. When you define a generic class or procedure, you do not have to define a separate version for each data type for which you might want to perform that functionality. - - An analogy is a screwdriver set with removable heads. You inspect the screw you need to turn and select the correct head for that screw (slotted, crossed, starred). Once you insert the correct head in the screwdriver handle, you perform the exact same function with the screwdriver, namely turning the screw. - - ![Diagram of a screwdriver set with different heads.](./media/generic-types/generic-screwdriver-set.gif) - - When you define a generic type, you parameterize it with one or more data types. This allows the using code to tailor the data types to its requirements. Your code can declare several different programming elements from the generic element, each one acting on a different set of data types. But the declared elements all perform the identical logic, no matter what data types they are using. - - For example, you might want to create and use a queue class that operates on a specific data type such as `String`. You can declare such a class from , as the following example shows. - - [!code-vb[VbVbalrDataTypes#1](~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrDataTypes/VB/Class1.vb#1)] - - You can now use `stringQ` to work exclusively with `String` values. Because `stringQ` is specific for `String` instead of being generalized for `Object` values, you do not have late binding or type conversion. This saves execution time and reduces run-time errors. - - For more information on using a generic type, see [How to: Use a Generic Class](how-to-use-a-generic-class.md). - -## Example of a Generic Class - - The following example shows a skeleton definition of a generic class. - - [!code-vb[VbVbalrDataTypes#2](~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrDataTypes/VB/Class1.vb#2)] - - In the preceding skeleton, `t` is a *type parameter*, that is, a placeholder for a data type that you supply when you declare the class. Elsewhere in your code, you can declare various versions of `classHolder` by supplying various data types for `t`. The following example shows two such declarations. - - [!code-vb[VbVbalrDataTypes#3](~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrDataTypes/VB/Class1.vb#3)] - - The preceding statements declare *constructed classes*, in which a specific type replaces the type parameter. This replacement is propagated throughout the code within the constructed class. The following example shows what the `processNewItem` procedure looks like in `integerClass`. - - [!code-vb[VbVbalrDataTypes#4](~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrDataTypes/VB/Class1.vb#4)] - - For a more complete example, see [How to: Define a Class That Can Provide Identical Functionality on Different Data Types](how-to-define-a-class-that-can-provide-identical-functionality.md). - -## Eligible Programming Elements - - You can define and use generic classes, structures, interfaces, procedures, and delegates. Note that the .NET Framework defines several generic classes, structures, and interfaces that represent commonly used generic elements. The namespace provides dictionaries, lists, queues, and stacks. Before defining your own generic element, see if it is already available in . - - Procedures are not types, but you can define and use generic procedures. See [Generic Procedures in Visual Basic](generic-procedures.md). - -## Advantages of Generic Types - - A generic type serves as a basis for declaring several different programming elements, each of which operates on a specific data type. The alternatives to a generic type are: - -1. A single type operating on the `Object` data type. - -2. A set of *type-specific* versions of the type, each version individually coded and operating on one specific data type such as `String`, `Integer`, or a user-defined type such as `customer`. - - A generic type has the following advantages over these alternatives: - -- **Type Safety.** Generic types enforce compile-time type checking. Types based on `Object` accept any data type, and you must write code to check whether an input data type is acceptable. With generic types, the compiler can catch type mismatches before run time. - -- **Performance.** Generic types do not have to *box* and *unbox* data, because each one is specialized for one data type. Operations based on `Object` must box input data types to convert them to `Object` and unbox data destined for output. Boxing and unboxing reduce performance. - - Types based on `Object` are also late-bound, which means that accessing their members requires extra code at run time. This also reduces performance. - -- **Code Consolidation.** The code in a generic type has to be defined only once. A set of type-specific versions of a type must replicate the same code in each version, with the only difference being the specific data type for that version. With generic types, the type-specific versions are all generated from the original generic type. - -- **Code Reuse.** Code that does not depend on a particular data type can be reused with various data types if it is generic. You can often reuse it even with a data type that you did not originally predict. - -- **IDE Support.** When you use a constructed type declared from a generic type, the integrated development environment (IDE) can give you more support while you are developing your code. For example, IntelliSense can show you the type-specific options for an argument to a constructor or method. - -- **Generic Algorithms.** Abstract algorithms that are type-independent are good candidates for generic types. For example, a generic procedure that sorts items using the interface can be used with any data type that implements . - -## Constraints - - Although the code in a generic type definition should be as type-independent as possible, you might need to require a certain capability of any data type supplied to your generic type. For example, if you want to compare two items for the purpose of sorting or collating, their data type must implement the interface. You can enforce this requirement by adding a *constraint* to the type parameter. - -### Example of a Constraint - - The following example shows a skeleton definition of a class with a constraint that requires the type argument to implement . - - [!code-vb[VbVbalrDataTypes#5](~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrDataTypes/VB/Class1.vb#5)] - - If subsequent code attempts to construct a class from `itemManager` supplying a type that does not implement , the compiler signals an error. - -### Types of Constraints - - Your constraint can specify the following requirements in any combination: - -- The type argument must implement one or more interfaces - -- The type argument must be of the type of, or inherit from, at most one class - -- The type argument must expose a parameterless constructor accessible to the code that creates objects from it - -- The type argument must be a *reference type*, or it must be a *value type* - - If you need to impose more than one requirement, you use a comma-separated *constraint list* inside braces (`{ }`). To require an accessible constructor, you include the [New Operator](../../../language-reference/operators/new-operator.md) keyword in the list. To require a reference type, you include the `Class` keyword; to require a value type, you include the `Structure` keyword. - - For more information on constraints, see [Type List](../../../language-reference/statements/type-list.md). - -### Example of Multiple Constraints - - The following example shows a skeleton definition of a generic class with a constraint list on the type parameter. In the code that creates an instance of this class, the type argument must implement both the and interfaces, be a reference type, and expose an accessible parameterless constructor. - - [!code-vb[VbVbalrDataTypes#6](~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrDataTypes/VB/Class1.vb#6)] - -## Important Terms - - Generic types introduce and use the following terms: - -- *Generic Type*. A definition of a class, structure, interface, procedure, or delegate for which you supply at least one data type when you declare it. - -- *Type Parameter*. In a generic type definition, a placeholder for a data type you supply when you declare the type. - -- *Type Argument*. A specific data type that replaces a type parameter when you declare a constructed type from a generic type. - -- *Constraint*. A condition on a type parameter that restricts the type argument you can supply for it. A constraint can require that the type argument must implement a particular interface, be or inherit from a particular class, have an accessible parameterless constructor, or be a reference type or a value type. You can combine these constraints, but you can specify at most one class. - -- *Constructed Type*. A class, structure, interface, procedure, or delegate declared from a generic type by supplying type arguments for its type parameters. - +# Generic types in Visual Basic (Visual Basic) + +A *generic type* is a single programming element that adapts to perform the same functionality for multiple data types. When you define a generic class or procedure, you don't have to define a separate version for each data type for which you might want to perform that functionality. + +An analogy is a screwdriver set with removable heads. You inspect the screw and select the correct head for that screw (slotted, crossed, starred). Once you insert the correct head in the screwdriver handle, you perform the exact same function with the screwdriver, namely turning the screw. + +:::image type="content" source="./media/generic-types/generic-screwdriver-set.gif" alt-text="Diagram of a screwdriver set with different heads."::: + +When you define a generic type, you parameterize it with one or more data types. Type parameters allow code to tailor the data types to its requirements. Your code can declare several different programming elements from the generic element, each one acting on a different set of data types. But the declared elements all perform the identical logic, no matter what data types they're using. + +For example, you might want to create and use a queue class that operates on a specific data type such as `String`. You can declare such a class from , as the following example shows. + +:::code language="visual-basic" source="~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrDataTypes/VB/Class1.vb" id="Snippet1"::: + +You can now use `stringQ` to work exclusively with `String` values. Because `stringQ` is specific for `String` instead of being generalized for `Object` values, you don't have late binding or type conversion. Generic types save execution time and reduce run-time errors. + +For more information on using a generic type, see [How to: Use a Generic Class](how-to-use-a-generic-class.md). + +## Example of a generic class + +The following example shows a skeleton definition of a generic class. + +:::code language="visual-basic" source="~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrDataTypes/VB/Class1.vb" id="Snippet2"::: + +In the preceding skeleton, `t` is a *type parameter*, that is, a placeholder for a data type that you supply when you declare the class. Elsewhere in your code, you can declare various versions of `classHolder` by supplying various data types for `t`. The following example shows two such declarations. + +:::code language="visual-basic" source="~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrDataTypes/VB/Class1.vb" id="Snippet3"::: + +The preceding statements declare *constructed classes*, in which a specific type replaces the type parameter. This replacement is propagated throughout the code within the constructed class. The following example shows what the `processNewItem` procedure looks like in `integerClass`. + +:::code language="visual-basic" source="~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrDataTypes/VB/Class1.vb" id="Snippet4"::: + +For a more complete example, see [How to: Define a Class That Can Provide Identical Functionality on Different Data Types](how-to-define-a-class-that-can-provide-identical-functionality.md). + +## Eligible programming elements + +You can define and use generic classes, structures, interfaces, procedures, and delegates. .NET defines several generic classes, structures, and interfaces that represent commonly used generic elements. The namespace provides dictionaries, lists, queues, and stacks. Before defining your own generic element, see if it's already available in . + +Procedures aren't types, but you can define and use generic procedures. See [Generic Procedures in Visual Basic](generic-procedures.md). + +## Advantages of generic types + +A generic type serves as a basis for declaring several different programming elements, each of which operates on a specific data type. The alternatives to a generic type are: + +1. A single type operating on the `Object` data type. +2. A set of *type-specific* versions of the type. Each version is individually coded and operating on one specific data type such as `String`, `Integer`, or a user-defined type such as `customer`. + +A generic type has the following advantages over these alternatives: + +- **Type Safety.** Generic types enforce compile-time type checking. Types based on `Object` accept any data type, and you must write code to check whether an input data type is acceptable. With generic types, the compiler can catch type mismatches before run time. +- **Performance.** Generic types don't have to *box* and *unbox* data, because each one is specialized for one data type. Operations based on `Object` must box input data types to convert them to `Object` and unbox data destined for output. Boxing and unboxing reduce performance. + Types based on `Object` are also late-bound, which means that accessing their members requires extra code at run time. Type conversions also reduce performance. +- **Code Consolidation.** The code in a generic type has to be defined only once. A set of type-specific versions of a type must replicate the same code in each version, with the only difference being the specific data type for that version. With generic types, the type-specific versions are all generated from the original generic type. +- **Code Reuse.** Code that doesn't depend on a particular data type can be reused with various data types if it's generic. You can often reuse it even with a data type that you didn't originally predict. +- **IDE Support.** When you use a constructed type declared from a generic type, the integrated development environment (IDE) can give you more support while you're developing your code. For example, IntelliSense can show you the type-specific options for an argument to a constructor or method. +- **Generic Algorithms.** Abstract algorithms that are type-independent are good candidates for generic types. For example, a generic procedure that sorts items using the interface can be used with any data type that implements . + +## Constraints + +Although the code in a generic type definition should be as type-independent as possible, you might need to require a certain capability of any data type supplied to your generic type. For example, if you want to compare two items to sort or collate, their data type must implement the interface. You can enforce this requirement by adding a *constraint* to the type parameter. + +### Example of a constraint + +The following example shows a skeleton definition of a class with a constraint that requires the type argument to implement . + +:::code language="visual-basic" source="~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrDataTypes/VB/Class1.vb" id="Snippet5"::: + +If subsequent code attempts to construct a class from `itemManager` supplying a type that doesn't implement , the compiler signals an error. + +### Types of constraints + +Your constraint can specify the following requirements in any combination: + +- The type argument must implement one or more interfaces +- The type argument must be of the type of, or inherit from, at most one class +- The type argument must expose a parameterless constructor accessible to the code that creates objects from it +- The type argument must be a *reference type*, or it must be a *value type* + +C# code can declare that a type argument must be an [*unmanaged type*](../../../../csharp/programming-guide/generics/constraints-on-type-parameters.md#unmanaged-constraint). Visual Basic enforces this constraint for Visual Basic code that uses a generic type or method that was defined with this constraint (in C#). However, you can't declare an `unmanaged` constraint on a type parameter in Visual Basic. + +If you need to impose more than one requirement, you use a comma-separated *constraint list* inside braces (`{ }`). To require an accessible constructor, you include the [New Operator](../../../language-reference/operators/new-operator.md) keyword in the list. To require a reference type, you include the `Class` keyword; to require a value type, you include the `Structure` keyword. + +For more information on constraints, see [Type List](../../../language-reference/statements/type-list.md). + +### Example of multiple constraints + +The following example shows a skeleton definition of a generic class with a constraint list on the type parameter. In the code that creates an instance of this class, the type argument must implement both the and interfaces, be a reference type, and expose an accessible parameterless constructor. + +:::code language="visual-basic" source="~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbalrDataTypes/VB/Class1.vb" id="Snippet6"::: + +## Important terms + +Generic types introduce and use the following terms: + +- *Generic Type*. A definition of a class, structure, interface, procedure, or delegate for which you supply at least one data type when you declare it. +- *Type Parameter*. In a generic type definition, a placeholder for a data type you supply when you declare the type. +- *Type Argument*. A specific data type that replaces a type parameter when you declare a constructed type from a generic type. +- *Constraint*. A condition on a type parameter that restricts the type argument you can supply for it. A constraint can require that the type argument implement a particular interface, inherit from a particular class, have an accessible parameterless constructor, or be a reference type or a value type. You can combine these constraints, but you can specify at most one base class. +- *Constructed Type*. A class, structure, interface, procedure, or delegate declared from a generic type by supplying type arguments for its type parameters. + ## See also - [Data Types](index.md) diff --git a/docs/visual-basic/programming-guide/language-features/procedures/overload-resolution.md b/docs/visual-basic/programming-guide/language-features/procedures/overload-resolution.md index e4630b8365b4e..cc7c0abea8b0b 100644 --- a/docs/visual-basic/programming-guide/language-features/procedures/overload-resolution.md +++ b/docs/visual-basic/programming-guide/language-features/procedures/overload-resolution.md @@ -1,7 +1,7 @@ --- description: "Learn more about: Overload Resolution (Visual Basic)" title: "Overload Resolution" -ms.date: 07/20/2015 +ms.date: 01/31/2025 helpviewer_keywords: - "Visual Basic code, procedures" - "overload resolution" @@ -10,51 +10,45 @@ helpviewer_keywords: - "procedure overloading [Visual Basic], overload resolution" - "signatures [Visual Basic], procedure" - "overloads [Visual Basic], resolution" -ms.assetid: 766115d1-4352-45fb-859f-6063e0de0ec0 --- -# Overload Resolution (Visual Basic) +# Overload resolution (Visual Basic) -When the Visual Basic compiler encounters a call to a procedure that is defined in several overloaded versions, the compiler must decide which of the overloads to call. It does this by performing the following steps: - -1. **Accessibility.** It eliminates any overload with an access level that prevents the calling code from calling it. - -2. **Number of Parameters.** It eliminates any overload that defines a different number of parameters than are supplied in the call. - -3. **Parameter Data Types.** The compiler gives instance methods preference over extension methods. If any instance method is found that requires only widening conversions to match the procedure call, all extension methods are dropped and the compiler continues with only the instance method candidates. If no such instance method is found, it continues with both instance and extension methods. - - In this step, it eliminates any overload for which the data types of the calling arguments cannot be converted to the parameter types defined in the overload. - -4. **Narrowing Conversions.** It eliminates any overload that requires a narrowing conversion from the calling argument types to the defined parameter types. This is true whether the type checking switch ([Option Strict Statement](../../../language-reference/statements/option-strict-statement.md)) is `On` or `Off`. - -5. **Least Widening.** The compiler considers the remaining overloads in pairs. For each pair, it compares the data types of the defined parameters. If the types in one of the overloads all widen to the corresponding types in the other, the compiler eliminates the latter. That is, it retains the overload that requires the least amount of widening. - -6. **Single Candidate.** It continues considering overloads in pairs until only one overload remains, and it resolves the call to that overload. If the compiler cannot reduce the overloads to a single candidate, it generates an error. - - The following illustration shows the process that determines which of a set of overloaded versions to call. - - ![Flow diagram of overload resolution process](./media/overload-resolution/determine-overloaded-version.gif "Resolving among overloaded versions") - - The following example illustrates this overload resolution process. - - [!code-vb[VbVbcnProcedures#62](~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbcnProcedures/VB/Class1.vb#62)] - - [!code-vb[VbVbcnProcedures#63](~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbcnProcedures/VB/Class1.vb#63)] - - In the first call, the compiler eliminates the first overload because the type of the first argument (`Short`) narrows to the type of the corresponding parameter (`Byte`). It then eliminates the third overload because each argument type in the second overload (`Short` and `Single`) widens to the corresponding type in the third overload (`Integer` and `Single`). The second overload requires less widening, so the compiler uses it for the call. - - In the second call, the compiler cannot eliminate any of the overloads on the basis of narrowing. It eliminates the third overload for the same reason as in the first call, because it can call the second overload with less widening of the argument types. However, the compiler cannot resolve between the first and second overloads. Each has one defined parameter type that widens to the corresponding type in the other (`Byte` to `Short`, but `Single` to `Double`). The compiler therefore generates an overload resolution error. - -## Overloaded Optional and ParamArray Arguments +The Visual Basic compiler must decide which overload to call when a procedure is defined in several overloaded versions. It decides by performing the following steps: + +1. **Accessibility.** It eliminates any overload with an access level that prevents the calling code from calling it. +1. **Number of Parameters.** It eliminates any overload that defines a different number of parameters than are supplied in the call. +1. **Parameter Data Types.** The compiler gives instance methods preference over extension methods. If any instance method is found that requires only widening conversions to match the procedure call, all extension methods are dropped. The compiler continues with only the instance method candidates. If no such instance method is found, it continues with both instance and extension methods. + In this step, it eliminates any overload for which the data types of the calling arguments can't be converted to the parameter types defined in the overload. +1. **Narrowing Conversions.** It eliminates any overload that requires a narrowing conversion from the calling argument types to the defined parameter types. This step takes place whether the type checking switch ([Option Strict Statement](../../../language-reference/statements/option-strict-statement.md)) is `On` or `Off`. +1. **Least Widening.** The compiler considers the remaining overloads in pairs. For each pair, it compares the data types of the defined parameters. If the types in one of the overloads all widen to the corresponding types in the other, the compiler eliminates the latter. That is, it retains the overload that requires the least amount of widening. +1. **Overload Resolution Priority.** The compiler removes any overload that has a lower than the highest value on any candidate overloads. Any overload without this attribute is assigned the default value of zero. +1. **Single Candidate.** It continues considering overloads in pairs until only one overload remains, and it resolves the call to that overload. If the compiler can't reduce the overloads to a single candidate, it generates an error. + +The following illustration shows the process that determines which of a set of overloaded versions to call. + +:::image type="content" source="./media/overload-resolution/determine-overloaded-version.gif" alt-text="Flow diagram of overload resolution process"::: + +The following example illustrates this overload resolution process. + +:::code language="visual-basic" source="~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbcnProcedures/VB/Class1.vb" id="Snippet62"::: + +:::code language="visual-basic" source="~/samples/snippets/visualbasic/VS_Snippets_VBCSharp/VbVbcnProcedures/VB/Class1.vb" id="Snippet63"::: + +In the first call, the compiler eliminates the first overload because the type of the first argument (`Short`) narrows to the type of the corresponding parameter (`Byte`). It then eliminates the third overload because each argument type in the second overload (`Short` and `Single`) widens to the corresponding type in the third overload (`Integer` and `Single`). The second overload requires less widening, so the compiler uses it for the call. + +In the second call, the compiler can't eliminate any of the overloads based on narrowing. It eliminates the third overload for the same reason as in the first call, because it can call the second overload with less widening of the argument types. However, the compiler can't resolve between the first and second overloads. Each has one defined parameter type that widens to the corresponding type in the other (`Byte` to `Short`, but `Single` to `Double`). The compiler therefore generates an overload resolution error. + +## Overloaded `Optional` and `ParamArray` arguments + +If two overloads of a procedure have identical signatures except that the last parameter is declared [Optional](../../../language-reference/modifiers/optional.md) in one and [ParamArray](../../../language-reference/modifiers/paramarray.md) in the other, the compiler resolves a call to that procedure as follows: + +|If the call supplies the last argument as|The compiler resolves the call to the overload declaring the last argument as| +|---|---| +|No value (argument omitted)|`Optional`| +|A single value|`Optional`| +|Two or more values in a comma-separated list|`ParamArray`| +|An array of any length (including an empty array)|`ParamArray`| - If two overloads of a procedure have identical signatures except that the last parameter is declared [Optional](../../../language-reference/modifiers/optional.md) in one and [ParamArray](../../../language-reference/modifiers/paramarray.md) in the other, the compiler resolves a call to that procedure as follows: - -|If the call supplies the last argument as|The compiler resolves the call to the overload declaring the last argument as| -|---|---| -|No value (argument omitted)|`Optional`| -|A single value|`Optional`| -|Two or more values in a comma-separated list|`ParamArray`| -|An array of any length (including an empty array)|`ParamArray`| - ## See also - [Optional Parameters](./optional-parameters.md)