Действительно ли перегрузка является единственным способом иметь аргументы функции по умолчанию в C#?

Проблема здесь в том, что shower - это тип interface. Типы интерфейсов в Go удерживают фактическое значение и его динамический тип. Подробнее об этом: Законы отражения # Представление интерфейса .

Выбранный фрагмент содержит 2 значения не nil. Второе значение представляет собой значение интерфейса, пару (значение; тип), содержащее значение nil и тип *display. Цитирование из спецификации языка g1] Go: Операторы сравнения :

Значения интерфейса сопоставимы. Два значения интерфейса равны, если они имеют одинаковые динамические типы и равные динамические значения или оба имеют значение nil.

blockquote>

Поэтому, если вы сравните его с nil, это будет false. Если вы сравните его со значением интерфейса, представляющим пару (nil;*display), это будет true:

if x == (*display)(nil) {
    panic("everything ok, nil found")
}

Это кажется неосуществимым, так как вам нужно знать, какой тип интерфейса имеет.

Почему это реализовано таким образом?

Интерфейсы, в отличие от других конкретных типов (не-интерфейсы), могут содержать значения разных типов конкретных типов (разные статические типы). Время выполнения должно знать динамический или runtime-тип значения, хранящегося в переменной типа интерфейса.

interface - это всего лишь набор методов, любой тип реализует его если одни и те же методы являются частью метода , заданного типа. Существуют типы, которые не могут быть nil, например struct или пользовательский тип с int в качестве базового типа. В этих случаях вам не нужно будет сохранять значение nil этого конкретного типа.

Но любой тип также включает конкретные типы, где nil является действительным (например, фрагменты, карты, каналы, все типы указателей), поэтому, чтобы сохранить значение во время выполнения, которое удовлетворяет интерфейсу, разумно поддерживать сохранение nil внутри интерфейса. Но помимо nil внутри интерфейса мы должны хранить его динамический тип, поскольку значение nil не несет такую ​​информацию. Альтернативным вариантом будет использование nil в качестве самого значения интерфейса, когда значение, которое будет храниться в нем, nil, но это решение недостаточно, так как оно потеряет информацию о динамическом типе.

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

blockquote>

В общем случае, если вы хотите указать nil для значения типа interface, используйте явное значение nil, а затем вы можете проверить равенство nil. Наиболее распространенным примером является встроенный тип error , который является интерфейсом с одним методом. Всякий раз, когда нет ошибки, вы явно устанавливаете или возвращаете значение nil, а не значение какой-либо конкретной (неинтерфейсной) ошибки типа типа (что было бы очень плохой практикой, см. Демонстрацию ниже).

В вашем примере путаница возникает из фактов, что:

  • вы хотите иметь значение в качестве типа интерфейса (shower)
  • , но значение, которое вы хотите хранить в срезе не тип shower, а конкретный тип

Поэтому, когда вы помещаете *display тип в срез shower, будет создано значение интерфейса, которое представляет собой пару (значение; тип), где значение равно nil, а тип - *display. Значение внутри пары будет nil, а не значением самого интерфейса. Если вы поместите значение nil в срез, то значение интерфейса себя будет nil, а условием x == nil будет true.

Демонстрация

См. этот пример: Игровая площадка

type MyErr string

func (m MyErr) Error() string {
    return "big fail"
}

func doSomething(i int) error {
    switch i {
    default:
        return nil // This is the trivial true case
    case 1:
        var p *MyErr
        return p // This will be false
    case 2:
        return (*MyErr)(nil) // Same as case 1
    case 3:
        var err error // Zero value is nil for the interface
        return err    // This will be true because err is already interface type
    case 4:
        var p *MyErr
        return error(p) // This will be false because the interface points to a
                        // nil item but is not nil itself.
    }
}

func main() {
    for i := 0; i <= 4; i++ {
        err := doSomething(i)
        fmt.Println(i, err, err == nil)
    }
}

Выход:

0  true
1  false
2  false
3  true
4  false

В случае 2 указатель nil но сначала он преобразуется в тип интерфейса (error), поэтому создается значение интерфейса, которое содержит значение nil и тип *MyErr, поэтому значение интерфейса не является nil.

10
задан Mark Biek 2 September 2008 в 17:32
поделиться

8 ответов

Да, это было бы лучшим, кроме Вы опустите $s на названиях параметра, как другие указали. Для заинтересованных объяснением позади отсутствия значений параметров по умолчанию, см. объяснение @Giovanni Galbo.

5
ответ дан 3 December 2019 в 14:54
поделиться

Относительно выборки от c# часто задаваемых вопросов:

Большинство проблем, перечисленных там, было решено для VB.Net (конкретно intellisense и проблемы комментариев xml), означая, что они - действительно отвлекающие маневры - существует код, доступный команде C#, которая решит проблему.

Другая причина имеет отношение к тому, чтобы вынуждать пользователя класса перекомпилировать, но это - определенный отвлекающий маневр, также. Если Вы изменяете значение по умолчанию в своем классе платформы, и пользователь не должен перекомпилировать, Вы рискуете пользователем, не знающим что измененное значение по умолчанию. Теперь у Вас есть потенциальная ошибка в коде, который не показывает вплоть до времени выполнения. Другими словами, альтернатива для перегрузки функции, по крайней мере, как плохо. Конечно, это также предполагает определенную реализацию функции, но это - реализация, предложенная в часто задаваемых вопросах.

Поэтому необходимо весить, остающаяся причина ("пытаются ограничить волшебство") по сравнению с фактом (который они подтверждают), что запись перегрузок "немного менее удобна". Лично, я говорю, вставляет функцию и позволяют программисту решить, использовать ли ее.

4
ответ дан 3 December 2019 в 14:54
поделиться

Только удовлетворить некоторое любопытство:

От того, Почему не делает параметров поддержки C# по умолчанию?:

На языках, таких как C++, значение по умолчанию может быть включено как часть объявления метода:

освободите Процесс (Сотрудник сотрудника, bool премия = ложь)

Этот метод можно назвать любым с:

a. Процесс (сотрудник, верный);

или

a. Процесс (сотрудник);

во втором случае премия параметра имеет значение false.

C# не имеет этой функции.

Одна причина у нас нет этой функции, связана с определенной реализацией функции. В мире C++, когда пользователь пишет:

a. Процесс (сотрудник);

компилятор генерирует

a.process (сотрудник, ложь);

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

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

Для компилятора было бы возможно взять что-то как определение C++ и произвести перегрузки, но существует несколько проблем с тем подходом.

Первый - то, что корреляция между кодом, который пользователь пишет и код компилятор, генерирует, менее очевидно. Мы обычно пытаемся ограничить волшебство, если это возможно, поскольку оно мешает программистам. Второй выпуск имеет отношение к вещам как комментарии документа XML и intellisense. Компилятор должен был бы иметь специальные правила для того, как он генерирует комментарии документа для перегруженных методов, и intellisense должен был бы иметь ум для сворачивания перегруженных методов в отдельный метод.

Запись перегрузок самостоятельно немного менее удобна, но мы думаем, что это - приемлемое решение.

20
ответ дан 3 December 2019 в 14:54
поделиться

Параметры по умолчанию являются частью C++, но с параметров по умолчанию C# 3.5 все еще не поддерживаются - необходимо будет перегрузиться. Они были доступны в VB.Net с тех пор 1.0.

2
ответ дан 3 December 2019 в 14:54
поделиться

Как указано, это не в настоящее время доступно в C# однако, они будут присутствовать в C# 4.0, как Sam Ng обсуждает на своем блоге:

http://blogs.msdn.com/samng/archive/2009/02/03/named-arguments-optional-arguments-and-default-values.aspx

0
ответ дан 3 December 2019 в 14:54
поделиться

Да.

Или приправление карри.

Или абстракция в класс и использование значений по умолчанию там.

0
ответ дан 3 December 2019 в 14:54
поделиться

Нет, AFAIK C# не поддерживает переопределение, и да, который является рекомендуемым способом выполнить тот же эффект.

0
ответ дан 3 December 2019 в 14:54
поделиться

самка это не делает задание?

void foo(int x):this(x, 0){}

void foo(int x, int y){
 // code here
}
0
ответ дан 3 December 2019 в 14:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: