Поделиться через


Перегрузка членов

Сигнатура члена содержит его имя и список параметров. Каждая сигнатура члена должна быть уникальной внутри типа. Члены могут иметь одинаковые имена, если их списки параметров различаются. Если два или более членов внутри типа являются членами одного вида (метод, свойство, конструктор и т. п.) и имеют одинаковые имена и различные списки параметров, говорят, что член перегружен. Например, класс Array содержит два метода CopyTo. Первый метод принимает массив и значение типа Int32, а второй принимает массив и значение типа Int64.

ПримечаниеПримечание

Изменение типа возвращаемого методом значения не делает метод уникальным, как указано в спецификации среды CLR.Нельзя определить перегрузку, отличающуюся только типом возвращаемого значения.

Перегруженные члены должны предоставлять различные варианты одних и тех же функциональных возможностей. Например, было бы неправильно создать для типа два члена CopyTo, один из которых копирует данные в массив, а второй — в файл. Обычно перегрузку члена используют для предоставления простых в использовании перегрузок, принимающих малое число параметров или не принимающих их. Эти члены вызывают более мощные перегрузки, для правильного применения которых, однако, от пользователя требуется больший опыт. Простые в использовании перегрузки поддерживают обычные сценарии, передавая значения по умолчанию сложным перегрузкам. Например, класс File предоставляет перегрузки для метода Open. Простая перегрузка Open принимает путь к файлу и файловый режим. Она вызывает перегрузку Open, которая принимает путь, файловый режим, параметры разрешений на доступ к файлу и общего доступа к нему и предоставляет обычно используемые значения по умолчанию для параметров разрешений на доступ к файлу и общего доступа к нему. Разработчикам, не нуждающимся в гибкости сложной перегрузки, не обязательно понимать структуру моделей доступа к файлу и общего доступа к нему, прежде чем открыть файл.

Для упрощения обслуживания и управления версиями более простые перегрузки должны использовать для выполнения действий сложные перегрузки; базовую функциональность не следует реализовывать в нескольких местах.

Рекомендации по реализации перегрузок

Следующие рекомендации помогут правильно разработать перегружаемые члены.

Старайтесь использовать описательные имена параметров для указания значения, используемого по умолчанию простыми перегрузками.

Особенно эта рекомендация относится к логическим параметрам типа Boolean. Имя параметра более сложной перегрузки должно указывать на значение по умолчанию, поставляемое более простой перегрузкой, путем описания противоположного состояния или действия. Например, класс String предоставляет следующие перегрузки:

Overloads Public Shared Function Compare( _
   ByVal strA As String, _
   ByVal strB As String _
) As Integer

Overloads Public Shared Function Compare( _
   ByVal strA As String, _
   ByVal strB As String, _
   ByVal ignoreCase As Boolean _
) As Integer
public static int Compare(
   string strA,
   string strB
);

public static int Compare(
   string strA,
   string strB,
   bool ignoreCase
);

Вторая перегрузка предоставляет параметр типа Boolean с именем ignoreCase. Он указывает на то, что более простая перегрузка учитывает регистр знаков и более сложную перегрузку следует использовать только тогда, когда учет регистра знаков не требуется. В общем случае значение по умолчанию должно быть false.

Избегайте произвольного изменения имен параметров в перегрузках. Если параметр в одной перегрузке представляет то же входное значение, что и параметр в другой перегрузке, параметры должны иметь одинаковые имена.

Например, не делайте следующего:

Public Sub Write(message as String, stream as FileStream)
End Sub
Public Sub Write(line as String, file as FileStream, closeStream as Boolean)
End Sub
public void Write(string message, FileStream stream){}
public void Write(string line, FileStream file, bool closeStream){}
public:
    void Write(String^ message, FileStream^ stream){}
    void Write(String^ line, FileStream^ file, bool closeStream){}

Ниже представлено правильное определение для этих перегрузок:

Public Sub Write(message as String, stream as FileStream)
End Sub
Public Sub Write(message as String, stream as FileStream, _
    closeStream as Boolean)
End Sub
public void Write(string message, FileStream stream){}
public void Write(string message, FileStream stream, bool closeStream){}
public:
    void Write(String^ message, FileStream^ stream){}
    void Write(String^ message, FileStream^ stream, bool closeStream){}

Будьте последовательны при упорядочении параметров в перегружаемых членах. Параметры с одинаковыми именами должны находиться во всех перегрузках на одном и том же месте.

Например, не делайте следующего:

Public Sub Write( message as String, stream as FileStream)
End Sub
Public Sub Write(stream as FileStream, message as String, _
    closeStream as Boolean)
End Sub
public void Write(string message, FileStream stream){}
public void Write(FileStream stream,  string message, bool closeStream){}
public:
    void Write(String^ message, FileStream^ stream){}
    void Write(FileStream^ stream, String^ message, bool closeStream){}

Ниже представлено правильное определение для этих перегрузок:

Public Sub Write(message as String, stream as FileStream)
End Sub
Public Sub Write(message as String, stream as FileStream, _
    closeStream as Boolean)
End Sub
public void Write(string message, FileStream stream){}
public void Write(string message, FileStream stream, bool closeStream){}
public:
    void Write(String^ message, FileStream^ stream){}
    void Write(String^ message, FileStream^ stream, bool closeStream){}

Для этой рекомендации имеется два ограничения.

  • Если перегрузка принимает изменяющийся список аргументов, этот список должен быть последним параметром.

  • Если перегрузка принимает параметры out, в соответствии со стандартом эти параметры должны быть последними.

Если требуется расширяемость, делайте виртуальной только самую длинную перегрузку ("Overridable" в Visual Basic). Более короткие перегрузки должны просто вызывать более длинную.

Этот метод продемонстрирован в следующем примере кода.

Public Sub Write(message as String, stream as FileStream)
    Me.Write(message, stream, false)
End Sub

Public Overridable Sub Write( _
    message as String, stream as FileStream, closeStream as Boolean)
    ' Do work here.
End Sub
public void Write(string message, FileStream stream)
{
    this.Write(message, stream, false);
}
public virtual void Write(string message, FileStream stream, bool closeStream)
{
    // Do work here.
}
public:
    void Write(String^ message, FileStream^ stream)
    {
        this->Write(message, stream, false);
    }

    virtual void Write(String^ message, FileStream^ stream, bool closeStream)
    {
        // Do work here.
    }

Не используйте модификаторы "ref" или "out" для перегрузки членов.

Например, не делайте следующего:

Public Sub Write(message as String,  count as Integer)


...


Public Sub Write(message as String, ByRef count as Integer)
public void Write(string message, int count)


...


public void Write(string message, out int count)
public:
    void Write(String^ message, int count)


...


void Write(String^ message, int% count)

Как правило, если возникает такая ситуация, то она является следствием более глубокой проблемы разработки. Рекомендуется переименовать один из членов, чтобы предоставить дополнительные сведения о точном действии, выполняемом методом.

Разрешите передавать значение "null" ("Nothing" в Visual Basic) для необязательных аргументов. Если метод принимает необязательные аргументы, являющиеся ссылочными типами, позвольте передавать им значение "null", чтобы указать не необходимость использования значения по умолчанию. Это поможет избежать проблемы необходимости проверки на наличие значения "null" перед вызовом члена.

Например, в следующем примере разработчикам не нужно выполнять проверку на наличие значения null.

Public Sub CopyFile (source as FileInfo, _
    destination as DirectoryInfo, _
    newName as string)

    If newName Is Nothing
        InternalCopyFile(source, destination) 
    Else
        InternalCopyFile(source, destination, newName)
    End If
End Sub
public void CopyFile (FileInfo source, DirectoryInfo destination, string newName)
{
    if (newName == null)
    {
        InternalCopyFile(source, destination);
    }
    else
    {
        InternalCopyFile(source, destination, newName);
    }
}
public:
    void CopyFile(FileInfo^ source, DirectoryInfo^ destination, String^ newName)
    {
        if (newName == nullptr)
       {
            InternalCopyFile(source, destination);
        }
        else
        {
            InternalCopyFile(source, destination, newName);
        }
    }

Использование перегрузки членов предпочтительнее, чем определение членов с аргументами по умолчанию. Аргументы по умолчанию не являются CLS-совместимыми и не могут быть использованы в некоторых языках.

В следующем примере кода демонстрируется неправильная разработка метода.

Public Sub Rotate (data as Matrix, Optional degrees as Integer = 180)
' Do rotation here
End Sub

В этом коде следует реализовать две перегрузки с более простой перегрузкой, предоставляющей значение по умолчанию. В следующем примере кода демонстрируется правильный подход.

Overloads Public Sub Rotate (data as Matrix)
    Rotate(data, 180)
End Sub

Overloads Public Sub Rotate (data as Matrix, degrees as Integer)
' Do rotation here
End Sub

Фрагменты — © Корпорация Майкрософт (Microsoft Corp.), 2005. Все права защищены.

Фрагменты — © Addison-Wesley Corporation. Все права защищены.

Для дополнительной информации о разработке руководящих принципов, смотрите "руководства по разработке рамок: Конвенций, идиомы и шаблоны для повторного использования.NET библиотек"книга, Кшиштоф Cwalina и Брэд Абрамс, опубликованных Addison-Wesley, 2005 года.

См. также

Другие ресурсы

Правила разработки членов

Руководство по разработке библиотек классов