Теоретически статический метод должен работать немного лучше, чем метод экземпляра, при прочих равных условиях, из-за дополнительного скрытого this
параметра.
На практике это так мало разницы, что будет скрыто в шуме различных решений компилятора. (Следовательно, два человека могут «доказать» один лучше другого с несовпадающими результатами). Не в последнюю очередь потому, что this
обычно передается в регистре и часто изначально находится в этом регистре.
Этот последний пункт означает, что теоретически мы должны ожидать, что статический метод, который принимает объект в качестве параметра и что-то с ним делает, будет немного хуже, чем эквивалент в качестве экземпляра для того же объекта. Опять же, разница настолько мала, что, если вы попытаетесь ее измерить, вы, вероятно, в конечном итоге примете какое-то другое решение компилятора. (Тем более, что вероятность того, что эта ссылка все время находится в регистре, тоже довольно высока).
Реальные различия в производительности будут зависеть от того, есть ли у вас в памяти искусственные объекты для выполнения чего-то, что естественно должно быть статическим, или вы запутываете цепочки передачи объектов сложными способами, чтобы делать то, что естественно должно быть экземпляром.
Следовательно, для номера 1. Когда сохранение состояния не является проблемой, всегда лучше быть статичным, потому что для этого статика и предназначена . Это не проблема производительности, хотя есть общее правило хорошей игры с оптимизацией компилятора - более вероятно, что кто-то приложил усилия для оптимизации случаев, которые возникают при нормальном использовании, чем тех, которые возникают со странным использованием.
Номер 2. Без разницы. Существует определенная сумма затрат на класс для каждого члена, она зависит как от количества метаданных, так и от количества кода в фактическом файле DLL или EXE, а также от количества измененного кода. Это одно и то же, будь то экземпляр или статический.
С пунктом 3 this
все как this
есть. Однако обратите внимание:
this
Параметр передается в конкретном регистре. При вызове метода экземпляра в том же классе он, скорее всего, уже будет в этом регистре (если он не был спрятан и регистр не использовался по какой-либо причине), и, следовательно, не требуется никаких действий для установки того, this
что ему нужно установить на . В определенной степени это относится, например, к первым двум параметрам метода, которые являются первыми двумя параметрами вызываемого им вызова.
Поскольку будет ясно, что this
это не NULL, в некоторых случаях это можно использовать для оптимизации вызовов.
Поскольку будет ясно, что this
это не null, это может снова сделать вызовы встроенных методов более эффективными, поскольку код, созданный для имитации вызова метода, может опускать некоторые проверки на null, которые могут потребоваться в любом случае.
Тем не менее, нулевые чеки дешевы!
Стоит отметить, что общие статические методы, действующие на объект, а не методы экземпляра, могут снизить некоторые затраты, обсуждаемые на http://joeduffyblog.com/2011/10/23/on-generics-and-some-of- the-associated-overheads / в случае, когда эта статика не вызывается для данного типа. По его словам, «в стороне, оказывается, что методы расширения - отличный способ сделать общие абстракции более выгодными».
Однако обратите внимание, что это относится только к созданию экземпляров других типов, используемых методом, которые иначе не существуют. Таким образом, он действительно не применяется во многих случаях (какой-то другой метод экземпляра использовал этот тип, какой-то другой код где-то еще использовал этот тип).
Резюме:
- В основном затраты на производительность экземпляра по сравнению со статическим ниже незначительны.
- Какие затраты обычно возникают при злоупотреблении статикой, например, или наоборот. Если вы не сделаете это частью своего выбора между статикой и экземпляром, у вас больше шансов получить правильный результат.
- В редких случаях статические универсальные методы в другом типе приводят к созданию меньшего количества типов, чем универсальные методы экземпляра, что иногда может иметь небольшое преимущество, так как становится редко используемым (и «редко» относится к тем типам, с которыми он используется в время жизни приложения, а не то, как часто оно вызывается). Как только вы поймете, о чем он говорит в этой статье, вы увидите, что в любом случае это на 100% не имеет отношения к большинству решений, связанных со статическим или экземпляром. Изменить: и в основном это стоит только с ngen, а не с jit-кодом.
Изменить: примечание о том, насколько дешевы нулевые проверки (что я утверждал выше). Большинство нулевых проверок в .NET вообще не проверяют наличие null, скорее они продолжают то, что собирались делать, с предположением, что это будет работать, и если возникает исключение доступа, оно превращается в файл NullReferenceException
. Таким образом, в большинстве случаев, когда концептуально код C # включает проверку на null, поскольку он обращается к члену экземпляра, стоимость в случае успеха фактически равна нулю. Исключением могут быть некоторые встроенные вызовы (потому что они хотят вести себя так, как если бы они вызывали член экземпляра), и они просто попадают в поле, чтобы вызвать такое же поведение, поэтому они также очень дешевы, и их все равно часто можно не учитывать. (например, если первый шаг в методе включал доступ к полю как есть).