Сводка
blockquote>Помимо понимания
Covariance-Contravariance
по опубликованным ссылкам, которые применимы к интерфейсам и делегатам, давайте разберемся в проблеме чуть подробнее, ниже приводится реализацияDictionary
, она реализуетIDictionary
, где оба типаTkey
иTValue
являются инвариантными, ни только ковариантными, ни только контравариантными, что просто означает, что они оба может находиться во входных и выходных позициях в зависимости от метода или свойства, конечно же, совместимость типов важна при реализации этих методов / свойств.Предположим, что следующий код является допустимым:
blockquote>
Dictionary
, тогда что он означает:: IDictionary Учитывая только [117 ], поскольку это только отличается, в Контравариантных позициях
in
, как иbool ContainsKey(TKey key);
, вы предоставляетеstring
, но он принимаетobject
, что хорошо, посколькуobject
является базовым классом, но Ковариантным Позицииout
будут проблемой, примерно какICollection
, так как вы готовы вернуть любоеKeys {get;} object
все, что есть в .Net C #, для типаobject
, но вызывающая сторона ожидает толькоstring
.Код выше даже не скомпилирует
blockquote>
Dictionary
код выше даже не скомпилирует, ваша путаница с точки зрения, если я могу назначитьstring
введите типobject
, то почему бы неDictionary
-IDictionary
, просто потому чтоDictionary
сама по себе является открытой реализацией универсального типа, которая закрывается, когда типы назначаются перед использованием, здесь отображение для типаDictionary
, который сам может быть назначен базовому классуobject
, а не для отдельных типов, используемых для создания закрытой структуры данных, поэтому важно сопоставлять их, чтобы гарантировать, что все методы с типами в любой позиции могут работать без проблем .Интересный случай
blockquote>IEnumerable
На самом деле,
IEnumerable
является интересным примером, он имеет ковариантныйtype T
], это базовый интерфейс для всех коллекций в .Net, здесь у нас может бытьList
, предоставленный вIEnumerable
, посколькуBaseclass
находится только в выходной позиции, поэтому может принять любой объект дочернего класса, фактически это несовместимость была одной из причин введения ковариации и контравариантности, в противном случае было бы невозможно выполнить присвоение с инвариантным типом, что не соответствовало ожиданиям разработчикафрагмент кода, чтобы понять разницу:
blockquote>void Main() { var list = new List
(); var dictionary = new Dictionary (); var isTrue = list is IEnumerable
я ++:
++ я:
возврата i С оптимизацией на, довольно возможно, что получающийся блок идентичен, однако ++ я более эффективен.
редактирование: имейте в виду, что в C++, я могу быть любым объектом, которые поддерживают префикс и постфикс ++ оператор. Для сложных объектов временная стоимость копии не незначительна.
Обычно в C++, постфикс потребует дополнительной конструкции увеличенного объекта, в то время как префикс применяется непосредственно к объекту. (Или таким образом, я читал.)
, Поскольку я не могу засвидетельствовать о том, как компилятор обрабатывает его из-за моих ограниченных знаний о вопросе, он мог быть обработан для Вас делающий это спорный вопрос.
Трудно ответить на это точно, поскольку это зависит от реализации компилятора/интерпретатора.
, Но вообще говоря, можно сказать, примерно расширяют меня ++ до следующих инструкций:
COPY i to tmp
INCREMENT tmp
SAVE tmp as i
, В то время как ++ я примерно расширюсь на:
LOAD i
INCREMENT i
Вы не можете только сказать, что ++ я быстрее, чем я ++, так как реализации языка довольно умны, и они могут оптимизировать эти инструкции, когда Вы знаете, что не получите доступ к временной ценности меня ++. Это обычно происходит в, говорят для цикла. Так во многих случаях это все равно.
, Если Вы пробуете к подобной микрооптимизации, я был бы совет Вы для представления/измерения прежде chosing один по другому.
Нет никакого права, или неправильно ответьте.
, Поскольку это зависит от:
, Как это было реализовано компилятором.
, На чем работает ЦП система.
, Если i
байт или i
, двойное слово
Это зависит от контекста, например:
x = i++
В этом случае, 'x' будет равен 'мне', и только после того, как это будет 'я' быть увеличенным одним.
x = ++i
В этом случае, 'я' буду увеличением одним, и затем новое значение 'x' будет присвоено 'x'.
В случае 'для' цикла, существует мало очевидной разницы кроме производительности (++, я быстрее).
Этот Stack Водосливный вопрос имеет большой ответ: там различие в производительности между мной ++ и ++ я в C?
я хотел бы добавить, что необходимо использовать, какой бы ни каждый удовлетворяет потребностям лучше. Кроме самого строго ограниченного во времени из приложений, это не важно. С академической точки зрения также, лучше написать код, который выражает то, в чем Вы нуждаетесь и оптимизируете наконец.
Нет никакого различия. Используйте конструкцию, которая имеет большую часть смысла.
, Если Ваше выполнение приложения медленно, я могу гарантировать Вам, что это никогда не будет из-за различий в скорости в целочисленной инкрементной операции. Если это, это - серьезная ошибка в компиляторе. Проблемами скорости в Вашем приложении будет алгоритмическая неэффективность, ожидающая ввода-вывода, и так далее.
не волнуются по поводу проблем, что Вы не имеете. Преждевременная оптимизация является корнем всего зла .
++ я беру тот меньше инструкции по процессору, чем я ++ в x86 блоке без оптимизации.
В целом более эффективно использовать ++ я, чем я ++. Простая причина этого состоит в том, что ++ я - крайне то же как
я + = 1;
, который для x86 является единственной инструкцией (и вероятно большая часть другой широко используемой архитектуры). я ++ однако равен
tmp = я; я + = 1;
Это вызвано тем, что старое значение 'я' - то, к чему я ++ оцениваю. И ясно который требует большего количества работы, чем просто я + = 1;
, Но как указано выше, это не оказывает фактически никакого влияния с достаточно умным компилятором, поскольку он оптимизирует неиспользованные операции далеко. Для многих интерпретируемых языков (пример: PHP), там вероятно минимальное усиление в скорости для ++ я; Но это увеличение незначительно.
Это обычно легче к типу i ++, следовательно это более эффективно с точки зрения времени производительности.
Серьезно, тем не менее, если я являюсь собственным типом данных (таким как интервал, дважды, и т.д.) - никакое различие.
И это - реализация, зависевшая, если это - пользовательский тип такой как
class Type
{
Type& operator ++(){}
const Type& operator ++(int i){}
};
T i;
Автономное "я ++"; или "++ я"; должен сгенерировать одинаково эффективный код. Различие прибывает при использовании его в выражении где "побочный эффект" играет роль.
Тем не менее было время, назад когда "все в мире Vax" и высосанные компиляторы, это ++ я, как говорили, был более эффективным что я ++, даже в "для (я = 0; я < N; ++ i)" установка типа.
Ну, в C++ я полагаю, что у них есть различное использование, в зависимости от того, когда Вы хотите обновленную переменную.
Эффективность не должна определять, когда Вы используете один по другому, но я предположил бы, что у них будет та же эффективность так или иначе.
++ мне не нужна временная переменная для хранения материала в. Думайте о них как это:
++ я
int preIncrement(int i)
{
i = i + 1;
return i;
}
я ++
int i = 5; // as an example
int postIncrement(_i)
{
int temp = _i;
i = _i + 1;
return temp;
}
Вижу? Постинкремент требует временной переменной. Принятие компилятора не улаживает все это для Вас, которых это почти наверняка делает.
, Конечно, более важный логика программы; Вы рискуете встречаться Печальная Трагедия театра Микрооптимизации , если Вы волнуетесь об этом слишком много... :)
++ я потенциально более эффективен для нетривиальной реализации оператора ++, но даже в том сценарии, компилятор может оптимизировать далеко промежуточный временный файл.
Эффективность не должна быть Вашим беспокойством: это значение . Эти два не то же, если они не автономны: каждый управляет предварительным использованием значения, другого сообщения.
интервал i; я = 1; суд < < я ++;//Возвраты 1
интервал i; я = 1; суд < < ++ я;//Возвраты 2
, Когда значение не важно, большинство компиляторов переведет и ++ я и я ++ (скажите в для цикла) в тот же код machine/VM.
Если я не пропускаю что-то, у них должна быть та же эффективность. Они должны оба привести к синглу, добавляет инструкция. Это - просто вопрос того, где добавить инструкция происходит: вначале или конец Вашей строки кода.
Это не имеет значения на современном компиляторе.
int v = i++;
совпадает с
int v = i;
i = i + 1;
А, современный компилятор обнаружит, что v
не использовано, и код для вычисления v
чист (никакие побочные эффекты). Затем это удалит v
и код присвоения и генерирует это
i = i + 1;
Это действительно имеет значение! Особенно, если Вы находитесь на C++...
++i // the prefered way, unless..
auto j = i++ // this is what you need
необходимо всегда использовать префиксную нотацию для предотвращения необходимого копирования наверху, и с C++ это имеет значение!
++i
быстрее, потому что i++
должен сохранить i
, затем увеличить его, затем возвратите хранимую сумму i
. ++i
просто инкременты i
затем возвраты это.
// ++i
i += 1;
return i;
// i++
temp = i;
i += 1;
return temp;