Статические методы и методы экземпляра в C#

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

Я помню, как читал, что статические методы быстрее, чем методы экземпляра, но не получают преимуществ GC. Это верно?

Маловероятно, что я изменю свой дизайн, если не найду лучшую альтернативу по дизайну, а не по скорости. Но все же для получения дополнительной информации я хочу знать разницу в скорости, GC и т. Д.

РЕДАКТИРОВАТЬ: Спасибо. Подробнее: Допустим, у нас есть класс Person:

class Person

который может иметь экземпляр метода Distance, например:

this.Distance (Person p)

Это здорово, но это не дает мне возможности вычислить расстояние между двумя точками (скажем, Point3) без создания экземпляров класса Person.

Я хочу сделать вот что:

class Person (no Distance methods)

но методы расширения Distance:

Distance (this Person, Person)
Distance (this Point3, Point3)

Таким образом, я могу:

myPerson.Distance (yourPerson)

а также

Extensions.Distance (pointA, pointB)

EDIT2: @Jon, да, я думаю, это было то, что имелось в виду (не получайте преимуществ GC), но я почему-то думал, что статические методы создают это бремя / накладные расходы.

Ответов (4)

Решение

Что вы имеете в виду, говоря «не пользуйтесь преимуществами GC»? Методы - это не сборщики мусора, а экземпляры.

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

Статические методы - это боль для тестирования - например, если вы аутентифицируетесь в методе Foo(), вызывая какой-то статический метод, тогда, когда вы тестируете, Foo() вы не можете заставить его просто вызвать фиктивный аутентификатор (если сам статический метод не позволяет вам сделать это. ). Однако, если вы предоставите исходный экземпляр того, что вы тестируете, имитирующую реализацию некоторого интерфейса, содержащего Authenticate() метод, вы можете заставить его вести себя так, как хотите.

РЕДАКТИРОВАТЬ: В этом случае похоже, что вам действительно нужен метод экземпляра для вашего Point типа, чтобы вычислить расстояние между двумя точками («это» одно и другое) - или, возможно, статический заводской метод для Distance типа.

Выбор между статическими методами и методами экземпляра - это вопрос объектно-ориентированного проектирования. Если метод, который вы пишете, является поведением объекта, то это должен быть метод экземпляра. Если он не зависит от экземпляра объекта, он должен быть статическим.

По сути, статические методы принадлежат типу, в то время как методы экземпляра принадлежат экземплярам типа.

Если под «быстрее» вы имеете в виду, что код внутри метода выполняется быстрее, тогда нет. Код в статическом методе так же быстр, как и код в нестатическом методе.

Если вы говорите о накладных расходах на выполнение вызова метода, он становится немного сложнее. Для таких языков, как Java, характерно то, что вызовы экземпляров имеют больше накладных расходов. Однако в C# это не так, поскольку методы экземпляра по умолчанию не являются виртуальными.

Таким образом, виртуальный метод имеет немного больше накладных расходов, чем не виртуальный метод. Статические методы не могут быть виртуальными, но методы экземпляра могут быть объявлены виртуальными.

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

Основываясь на вашем примере, я бы написал статическую служебную функцию, чтобы найти расстояние между двумя точками:

public static class Geometry
{
    public static double GetDistanceBetween(Point a, Point b) { ... }
}

А затем я бы дал Person свойство под названием Position, которое возвращает точку. Так что я мог написать:

double distance = Geometry.GetDistanceBetween(personA.Position, personB.Position);

Он уже практически на английском языке - зачем делать его более неясным? Если вы сделаете Distance методом, вы можете написать:

personA.Distance(personB)

или:

personB.Distance(personA)

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