Конструктор параметровParameter design

В этом разделе приводятся общие рекомендации по проектированию параметров, включая разделы с рекомендациями по проверке аргументов.This section provides broad guidelines on parameter design, including sections with guidelines for checking arguments. Кроме того, следует ознакомиться с рекомендациями, описанными в разделе параметры именования.In addition, you should refer to the guidelines described in Naming Parameters.

✔️ использовать тип наименее производного параметра, который предоставляет функциональные возможности, необходимые для элемента.✔️ DO use the least derived parameter type that provides the functionality required by the member.

Например, предположим, что требуется разработать метод, который перечисляет коллекцию и выводит каждый элемент на консоль.For example, suppose you want to design a method that enumerates a collection and prints each item to the console. Такой метод должен принимать IEnumerable в качестве параметра, а не ArrayList или IList, например.Such a method should take IEnumerable as the parameter, not ArrayList or IList, for example.

❌ не использовать зарезервированные параметры.❌ DO NOT use reserved parameters.

Если в какой-либо будущей версии требуется больше входных данных для члена, можно добавить новую перегрузку.If more input to a member is needed in some future version, a new overload can be added.

❌ не имеют общедоступных методов, которые принимают указатели, массивы указателей или многомерные массивы в качестве параметров.❌ DO NOT have publicly exposed methods that take pointers, arrays of pointers, or multidimensional arrays as parameters.

Указатели и многомерные массивы относительно сложно правильно использовать.Pointers and multidimensional arrays are relatively difficult to use properly. В большинстве случаев можно перерабатывать API, чтобы избежать использования этих типов в качестве параметров.In almost all cases, APIs can be redesigned to avoid taking these types as parameters.

✔️ поместить все параметры out после всех параметров по значению и ref (за исключением массивов параметров), даже если это приводит к несогласованности в порядке параметров между перегрузками (см. раздел перегрузка членов).✔️ DO place all out parameters following all of the by-value and ref parameters (excluding parameter arrays), even if it results in an inconsistency in parameter ordering between overloads (see Member Overloading).

Параметры out могут рассматриваться как дополнительные возвращаемые значения, и их группирование позволяет проще понять сигнатуру метода.The out parameters can be seen as extra return values, and grouping them together makes the method signature easier to understand.

✔️ быть единообразными в параметрах именования при переопределении членов или реализации членов интерфейса.✔️ DO be consistent in naming parameters when overriding members or implementing interface members.

Это улучшает связь между методами.This better communicates the relationship between the methods.

Выбор между перечислением и логическими параметрамиChoose between enum and boolean parameters

✔️ использовать перечисления, если элемент в противном случае будет иметь два или более логических параметра.✔️ DO use enums if a member would otherwise have two or more Boolean parameters.

❌ не используют логические значения, если нет уверенности в том, что больше не будет необходимости более двух значений.❌ DO NOT use Booleans unless you are absolutely sure there will never be a need for more than two values.

Перечисления предоставляют некоторое место для добавления значений в будущем, но следует помнить о всех последствиях добавления значений к перечислениям, которые описаны в статье о структуре перечисления.Enums give you some room for future addition of values, but you should be aware of all the implications of adding values to enums, which are described in Enum Design.

✔️ Рассмотрите возможность использования логических значений для параметров конструктора, которые действительно являются двумя состояниями, и просто используются для инициализации логических свойств.✔️ CONSIDER using Booleans for constructor parameters that are truly two-state values and are simply used to initialize Boolean properties.

Проверить аргументыValidate arguments

✔️ проверить аргументы, передаваемые в открытые, защищенные или явно реализованные члены.✔️ DO validate arguments passed to public, protected, or explicitly implemented members. Вызовите System.ArgumentExceptionили один из его подклассов, если проверка завершается неудачно.Throw System.ArgumentException, or one of its subclasses, if the validation fails.

Обратите внимание, что фактическая проверка не обязательно должна выполняться в самом открытом или защищенном члене.Note that the actual validation does not necessarily have to happen in the public or protected member itself. Это может произойти на более низком уровне в некоторых частных или внутренних подпрограммых.It could happen at a lower level in some private or internal routine. Главным моментом является то, что вся контактная зона, предоставляемая конечным пользователям, проверяет аргументы.The main point is that the entire surface area that is exposed to the end users checks the arguments.

✔️ Вызывайте ArgumentNullException, если передается аргумент NULL и член не поддерживает аргументы null.✔️ DO throw ArgumentNullException if a null argument is passed and the member does not support null arguments.

✔️ проверить параметры перечисления.✔️ DO validate enum parameters.

Не представим, что аргументы перечисления будут находиться в диапазоне, определенном перечислением.Do not assume enum arguments will be in the range defined by the enum. Среда CLR позволяет приведение любого целочисленного значения к значению перечисления, даже если оно не определено в перечислении.The CLR allows casting any integer value into an enum value even if the value is not defined in the enum.

❌ не используют Enum.IsDefined для проверок диапазона перечисления.❌ DO NOT use Enum.IsDefined for enum range checks.

✔️ Имейте в виду, что изменяемые аргументы могли измениться после проверки.✔️ DO be aware that mutable arguments might have changed after they were validated.

Если элемент защищен с учетом безопасности, рекомендуется создать копию, а затем проверить и обработать аргумент.If the member is security sensitive, you are encouraged to make a copy and then validate and process the argument.

Передать параметрыPass parameters

С точки зрения конструктора инфраструктуры существуют три основные группы параметров: параметры по значению, параметры ref и параметры out.From the perspective of a framework designer, there are three main groups of parameters: by-value parameters, ref parameters, and out parameters.

Когда аргумент передается через параметр по значению, член получает копию фактического аргумента, переданного в.When an argument is passed through a by-value parameter, the member receives a copy of the actual argument passed in. Если аргумент является типом значения, в стек помещается копия аргумента.If the argument is a value type, a copy of the argument is put on the stack. Если аргумент является ссылочным типом, в стек помещается копия ссылки.If the argument is a reference type, a copy of the reference is put on the stack. Наиболее популярные языки CLR, такие как C#, Visual Basic и C++, по умолчанию передают параметры по значению.Most popular CLR languages, such as C#, Visual Basic, and C++, default to passing parameters by value.

Когда аргумент передается через параметр ref, член получает ссылку на фактический аргумент, переданный в.When an argument is passed through a ref parameter, the member receives a reference to the actual argument passed in. Если аргумент является типом значения, в стек помещается ссылка на аргумент.If the argument is a value type, a reference to the argument is put on the stack. Если аргумент является ссылочным типом, ссылка на ссылку помещается в стек.If the argument is a reference type, a reference to the reference is put on the stack. Ref параметры можно использовать, чтобы разрешить члену изменять аргументы, передаваемые вызывающим объектом.Ref parameters can be used to allow the member to modify arguments passed by the caller.

Параметры Out похожи на параметры ref и некоторые небольшие различия.Out parameters are similar to ref parameters, with some small differences. Параметр изначально считается неназначенным и не может быть прочитан в теле элемента до того, как ему будет присвоено какое-либо значение.The parameter is initially considered unassigned and cannot be read in the member body before it is assigned some value. Кроме того, параметру необходимо назначить некоторое значение перед возвратом члена.Also, the parameter has to be assigned some value before the member returns.

❌ избегать использования параметров out и ref.❌ AVOID using out or ref parameters.

Для использования параметров out или ref требуется взаимодействие с указателями, понимание того, как типы значений и ссылочные типы различаются, и обрабатывает методы с несколькими возвращаемыми значениями.Using out or ref parameters requires experience with pointers, understanding how value types and reference types differ, and handling methods with multiple return values. Кроме того, различие между параметрами out и ref не является широко понятным.Also, the difference between out and ref parameters is not widely understood. Архитекторы платформ, разрабатываемые для общей аудитории, не должны ждать, чтобы пользователи работали с out или ref параметрами.Framework architects designing for a general audience should not expect users to master working with out or ref parameters.

❌ не передавать ссылочные типы по ссылке.❌ DO NOT pass reference types by reference.

Существует несколько ограниченных исключений правила, например метод, который может использоваться для замены ссылок.There are some limited exceptions to the rule, such as a method that can be used to swap references.

Члены с переменным числом параметровMembers with variable number of parameters

Члены, которые могут принимать переменное число аргументов, выражаются путем предоставления параметра массива.Members that can take a variable number of arguments are expressed by providing an array parameter. Например, String предоставляет следующий метод:For example, String provides the following method:

public class String {
    public static string Format(string format, object[] parameters);
}

Затем пользователь может вызвать метод String.Format следующим образом:A user can then call the String.Format method, as follows:

String.Format("File {0} not found in {1}",new object[]{filename,directory});

Добавление ключевого слова C# params в параметр массива приводит к изменению параметра на так называемый параметр массива params и предоставляет ярлык для создания временного массива.Adding the C# params keyword to an array parameter changes the parameter to a so-called params array parameter and provides a shortcut to creating a temporary array.

public class String {
    public static string Format(string format, params object[] parameters);
}

Это позволяет пользователю вызывать метод, передавая элементы массива непосредственно в списке аргументов.Doing this allows the user to call the method by passing the array elements directly in the argument list.

String.Format("File {0} not found in {1}",filename,directory);

Обратите внимание, что ключевое слово params можно добавить только к последнему параметру в списке параметров.Note that the params keyword can be added only to the last parameter in the parameter list.

✔️ РЕКОМЕНДУЕТСЯ добавить ключевое слово params к параметрам массива, если предполагается, что конечные пользователи будут передавать массивы с небольшим числом элементов.✔️ CONSIDER adding the params keyword to array parameters if you expect the end users to pass arrays with a small number of elements. Если предполагается, что множество элементов будет передаваться в типичных сценариях, пользователи, вероятно, не будут передавать эти элементы в любом случае, поэтому ключевое слово params не требуется.If it’s expected that lots of elements will be passed in common scenarios, users will probably not pass these elements inline anyway, and so the params keyword is not necessary.

❌ избегать использования массивов params, если вызывающий объект почти всегда будет иметь входные данные, уже имеющиеся в массиве.❌ AVOID using params arrays if the caller would almost always have the input already in an array.

Например, члены с параметрами массива байтов почти никогда не вызываются путем передачи отдельных байтов.For example, members with byte array parameters would almost never be called by passing individual bytes. По этой причине параметры массива байтов в .NET Framework не используют ключевое слово params.For this reason, byte array parameters in the .NET Framework do not use the params keyword.

❌ не использовать массивы params, если массив изменяется членом, принимающим параметр массива params.❌ DO NOT use params arrays if the array is modified by the member taking the params array parameter.

Из-за того, что многие компиляторы переключают аргументы в временный массив в месте вызова, массив может быть временным объектом, поэтому любые изменения массива будут потеряны.Because of the fact that many compilers turn the arguments to the member into a temporary array at the call site, the array might be a temporary object, and therefore any modifications to the array will be lost.

✔️ Рассмотрите возможность использования ключевого слова params в простой перегрузке, даже если более сложная перегрузка не может его использовать.✔️ CONSIDER using the params keyword in a simple overload, even if a more complex overload could not use it.

Задайте себе, если бы пользователь мог бы получить значение массива params в одной перегрузке, даже если это не было во всех перегрузках.Ask yourself if users would value having the params array in one overload even if it wasn’t in all overloads.

✔️ Попытайтесь Упорядочить параметры, чтобы можно было использовать ключевое слово params.✔️ DO try to order parameters to make it possible to use the params keyword.

✔️ Рассмотрите возможность предоставления специальных перегрузок и путей кода для вызовов с небольшим количеством аргументов в чрезвычайно чувствительных к производительности API.✔️ CONSIDER providing special overloads and code paths for calls with a small number of arguments in extremely performance-sensitive APIs.

Это позволяет избежать создания объектов Array при вызове API с небольшим числом аргументов.This makes it possible to avoid creating array objects when the API is called with a small number of arguments. Произведение имен параметров путем создания единственного значения параметра массива и добавления числового суффикса.Form the names of the parameters by taking a singular form of the array parameter and adding a numeric suffix.

Это следует делать только в том случае, если вы собираетесь использовать весь путь к коду, а не просто создаете массив и вызываете более общий метод.You should only do this if you are going to special-case the entire code path, not just create an array and call the more general method.

✔️ Помните, что значение NULL можно передать как аргумент массива params.✔️ DO be aware that null could be passed as a params array argument.

Перед обработкой необходимо проверить, что массив не равен null.You should validate that the array is not null before processing.

❌ не использовать методы varargs, в противном случае называемые многоточием.❌ DO NOT use the varargs methods, otherwise known as the ellipsis.

Некоторые языки CLR, такие как C++, поддерживают альтернативное соглашение для передачи списков параметров переменных, именуемых varargs методами.Some CLR languages, such as C++, support an alternative convention for passing variable parameter lists called varargs methods. Это соглашение не должно использоваться в платформах, поскольку оно несовместимо с CLS.The convention should not be used in frameworks, because it is not CLS compliant.

Параметры указателяPointer parameters

Как правило, указатели не должны отображаться в общедоступной контактной зоне хорошо спроектированной инфраструктуры управляемого кода.In general, pointers should not appear in the public surface area of a well-designed managed code framework. В большинстве случаев указатели должны быть инкапсулированы.Most of the time, pointers should be encapsulated. Однако в некоторых случаях указатели необходимы для обеспечения взаимодействия, и использование указателей в таких случаях уместно.However, in some cases pointers are required for interoperability reasons, and using pointers in such cases is appropriate.

✔️ предоставить альтернативу любому элементу, принимающему аргумент-указатель, поскольку указатели не являются CLS-совместимыми.✔️ DO provide an alternative for any member that takes a pointer argument, because pointers are not CLS-compliant.

❌ избежать дорогостоящей проверки аргументов указателей.❌ AVOID doing expensive argument checking of pointer arguments.

При проектировании элементов с указателями ✔️ следовать общим соглашениям, связанным с указателем.✔️ DO follow common pointer-related conventions when designing members with pointers.

Например, нет необходимости передавать начальный индекс, так как для достижения того же результата можно использовать простые арифметические операции с указателями.For example, there is no need to pass the start index, because simple pointer arithmetic can be used to accomplish the same result.

Части © 2005, 2009 Корпорация Майкрософт. Все права защищены.Portions © 2005, 2009 Microsoft Corporation. All rights reserved.

Перепечатано с разрешения Pearson Education, Inc. из книги Инфраструктура программных проектов. Соглашения, идиомы и шаблоны для многократно используемых библиотек .NET (2-е издание), авторы: Кржиштоф Цвалина (Krzysztof Cwalina) и Брэд Абрамс (Brad Abrams). Книга опубликована 22 октября 2008 г. издательством Addison-Wesley Professional в рамках серии, посвященной разработке для Microsoft Windows.Reprinted by permission of Pearson Education, Inc. from Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries, 2nd Edition by Krzysztof Cwalina and Brad Abrams, published Oct 22, 2008 by Addison-Wesley Professional as part of the Microsoft Windows Development Series.

См. также разделSee also