Понимание интерфейсов

Я широко использовал JetBrains dotTrace и Redgate ANTS . Они довольно похожи по характеристикам и цене. Они оба предлагают полезное профилирование производительности и довольно простое профилирование памяти.

dotTrace интегрируется с Resharper, что очень удобно, так как вы можете профилировать производительность модульного теста одним щелчком мыши из IDE. Однако часто кажется, что dotTrace дает ложные результаты (например, говоря, что метод занял несколько лет)

Я предпочитаю, чтобы ANTS представлял результаты профилирования. Он показывает вам исходный код и слева от каждой строки указывает, сколько времени потребовалось для запуска. У dotTrace просто дерево.

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

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

Бесплатный профилировщик Microsoft CLR ( .Net framework 2.0 / .Net Framework 4.0 ) - это все, что вам нужно для профилирования памяти .NET.

2011 Обновление:

Профилировщик памяти Scitech имеет довольно простой пользовательский интерфейс, но много полезной информации, включая некоторую информацию о неуправляемой памяти, которой нет у dotTrace и ANTS - вы можете найти это полезным, если вы делаете COM-взаимодействие, но мне еще предстоит найти какой-либо профилировщик, который бы облегчал диагностику проблем с памятью COM - вам, как правило, приходится выходить из этого windbg.exe.

Профилировщик ANTS за последние несколько лет начал стремительно развиваться, и его профилировщик памяти имеет некоторые действительно полезные функции, которые теперь, по моим оценкам, выдвинули его впереди dotTrace как пакета. Мне повезло, что у меня есть лицензии для обоих, но если вы собираетесь купить один .Net-профилировщик для производительности и памяти, сделайте его ANTS.

16
задан Cœur 15 August 2017 в 08:39
поделиться

9 ответов

Интерфейсы определяют контракты .

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

Что более важно, так это то, что вы можете использовать реальный объект FormsAuthenticationWrapper , но вы также можете реализовать свой собственный тип IFormsAuthentication , который вообще не имеет ничего общего с классом оболочки. Интерфейс сообщает вам, какие методы и свойства вам необходимо реализовать для выполнения контракта, и позволяет компилятору проверить, действительно ли ваш объект соблюдает этот контракт (до некоторой степени - контракт просто соблюдать по имени, но не по духу) , и поэтому вы не Если вы не хотите, вам придется использовать предварительно созданный FormsAuthenticationWrapper . Вы можете создать другой класс, который работает совершенно по-другому, но при этом соблюдает требуемый контракт.

В этом отношении интерфейсы очень похожи на обычное наследование с одним важным отличием. В C # класс может наследовать только от одного типа, но может реализовывать множество интерфейсов. Таким образом, интерфейсы позволяют выполнять несколько контрактов в одном классе. Объект может быть объектом IFormsAuthentication, а также быть чем-то другим, например IEnumerable.

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

void OutputValues(string[] values)
{
   foreach (string value in values)
   {
       Console.Writeline(value);
   }
}

Это принимает массив и выводит его на консоль. Теперь примените это простое изменение для использования интерфейса:

void OutputValues(IEnumerable<string> values)
{
   foreach (string value in values)
   {
       Console.Writeline(value);
   }
}

Этот код по-прежнему берет массив и выводит его на консоль. Но он также принимает List или что-нибудь еще, что вы хотите предоставить ему, что реализует IEnumerable . Итак, мы взяли интерфейс и использовали его, чтобы сделать простой блок кода намного более мощным.

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

И последнее замечание: когда я вижу интерфейс с такой реализацией оболочки "по умолчанию", я считаю это чем-то вроде anit-pattern или, по крайней мере, запахом кода. Это указывает мне на то, что, возможно, интерфейс слишком сложен, и вам нужно либо разделить его, либо рассмотреть возможность использования некоторой комбинации композиции + событий + делегатов, а не деривации, чтобы выполнить то же самое.

14
ответ дан 30 November 2019 в 15:38
поделиться

Я приведу вам пример ниже, но позвольте мне начать с одного из ваших утверждений. «Я не знаю, как определить, когда его использовать». поставить на край. Вам не нужно определять, когда его использовать, а когда нет. Любой параметр (по крайней мере, для общедоступных методов), любое (общедоступное) свойство (и лично я бы фактически расширил список до всего остального) должен быть объявлен как нечто вроде интерфейса, а не определенного класса. Единственный раз, когда я когда-либо объявлял что-то определенного типа, это когда не было подходящего интерфейса.

Я бы пошел

IEnumerable<T> sequence;

, когда смогу, и почти никогда (единственный случай, о котором я могу подумать, - это действительно ли я нужен метод ForEach)

List<T> sequence;

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

Цены на автомобили получены с набора веб-сайтов, а цены на компьютеры - с набора услуг.

решением может быть: создать одну веб-страницу, скажем, с сеткой данных и инъекцией зависимостей IDataRetriever если вы используете внедрение и интерфейсы, вы можете легко заменить производственный класс на тестирующий класс при тестировании. (Это снова может быть переключение хранилищ данных или принудительное выполнение ошибки, которую может быть очень сложно создать в коде выпуска, например, состояние гонки)

2
ответ дан 30 November 2019 в 15:38
поделиться

Возможно, лучший способ получить хорошее представление об интерфейсах - это использовать пример из .NET framework.

Рассмотрим следующую функцию:

void printValues(IEnumerable sequence)
{
    foreach (var value in sequence)
        Console.WriteLine(value);
}

Теперь я мог бы написать эту функцию принять List , объект [] или любой другой тип конкретной последовательности. Но поскольку я написал эту функцию, чтобы принимать параметр типа IEnumerable , это означает, что я могу передать любой конкретный тип в эту функцию, которая реализует интерфейс IEnumerable .

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

10
ответ дан 30 November 2019 в 15:38
поделиться

Хорошо, мне тоже сначала было трудно понять, так что не беспокойтесь об этом.

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

public class Character
{
}

Теперь предположим, что я хочу, чтобы у персонажа было оружие. Я мог бы использовать интерфейс для определения методов, необходимых для оружия:

interface IWeapon
{
    public Use();
}

Итак, давайте дадим персонажу оружие:

public class Character
{
    IWeapon weapon;

    public void GiveWeapon(IWeapon weapon)
    {
        this.weapon = weapon;
    }

    public void UseWeapon()
    {
        weapon.Use();
    }
}

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

public class Gun : IWeapon
{
    public void Use()
    {
        Console.Writeline("Weapon Fired");
    }
}

Затем вы можете склеить его вместе:

Character bob = new character();
Gun pistol = new Gun();
bob.GiveWeapon(pistol);
bob.UseWeapon();

Теперь это общий пример, но дает много силы. Вы можете прочитать об этом больше, если посмотрите Стратегический паттерн.

17
ответ дан 30 November 2019 в 15:38
поделиться

Я понял это следующим образом:

Деривация - это отношение «есть-есть», например, Собака - это животное, Корова - это животное, но интерфейс никогда не выводится, это реализовано.

Итак, интерфейс - это отношения «возможного», например, собака может быть собакой-шпионом, собака может быть цирковой собакой и т. Д. Но для этого собака должна научиться некоторым определенным вещам. Что в терминологии объектно-ориентированного программирования означает, что ваш класс должен иметь возможность делать некоторые определенные вещи (контракт, как они его называют), если он реализует интерфейс. например, если ваш класс реализует IEnumerable, это явно означает, что ваш класс имеет (должен иметь) такую ​​функциональность, чтобы его объекты можно было перечислить.

Таким образом, по сути, посредством реализации интерфейса класс предоставляет своим пользователям функциональность, которую он может что-то делать, но это НЕ наследование.

1
ответ дан 30 November 2019 в 15:38
поделиться

Мы используем интерфейсы (или абстрактные базовые классы), чтобы разрешить полиморфизм, который является очень центральной концепцией в объектно-ориентированном программировании. . Это позволяет нам очень гибко составлять поведение. Если вы еще этого не сделали, вам следует прочитать Шаблоны проектирования - он содержит множество примеров использования интерфейсов.

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

В частности, при работе с веб-разработкой многие службы, на которые мы полагаемся (например, контекст HTTP) недоступен, когда код выполняется вне веб-контекста, но если мы скроем эту функциональность за интерфейсом,

1
ответ дан 30 November 2019 в 15:38
поделиться

Веб-служба позволит вам кэшировать данные, уменьшая нагрузку на базу данных. Это также упростит предоставление данных из вашей системы другим системам. Еще одна вещь - гибкость - с веб-службой в качестве другого уровня вы можете изменить строку подключения / изменения схемы для всех клиентов в одном месте, вам не придется перераспределять клиента.
Вам когда-нибудь понадобится что-нибудь из этого? Я обычно не использую парадигмы, как вы говорите, но я думаю, что веб-сервис может иметь смысл. Тем не менее, только вы знаете, как устроено ваше приложение: сколько людей будет использовать этот клиент? Требуется ли для подключения к серверу MySQL какое-либо специальное программное обеспечение / конфигурация на клиентском компьютере? (Oracle делает, например).

метод Add, приведенный выше, возвращает int, и аргументы, которые метод ожидает передать ему вызывающими объектами

Методы обычно считаются чем-то, что может делать объект; приведенный выше пример подразумевает, что класс, в котором определен метод, работает с числа

Тело метода точно описывает (в коде), как объект выполняет действие, описанное в имени метода. В приведенном выше примере метод добавления работает, применяя к параметрам оператор сложения и возвращая результат.

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

Другими словами, интерфейс может описывать действия (методы) класса, но он никогда не должен описывать, как должно выполняться действие.

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

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

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

public class Plugin
{
public void Run (PluginHost browser)
{
//do stuff here....
}
}

Но как могли бы вы разумно реализовать этот метод? Вы не можете точно знать, как будет работать каждый возможный будущий плагин

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

public interface IPlugin
{
void Run(PluginHost browser);
}

public class PluginHost
{
public void RunPlugins (IPlugin[] plugins)
{
foreach plugin in plugins
{
plugin.Run(this);
}
}
}

Обратите внимание, что как обсуждалось ранее, интерфейс IPlugin описывает метод Run, но не указывает, как Run это делает.

5
ответ дан 30 November 2019 в 15:38
поделиться

Так как почти все написано об интерфейсах, позвольте мне попробовать.

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

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

В сочетании с поддержкой полиморфизма можно использовать интерфейсы для написания более чистых и динамический код.

например.

Интерфейс livingBeings

- speak () // говорит любой, кто IS liveBeing, должен определить, как они говорят

класс собака реализует livingBeings

- speak () {bark;} // реализация «Говори как собака»

класс Bird реализует livingBeings

- Speak () {chirp;} // Реализация «Говори как птица»

1
ответ дан 30 November 2019 в 15:38
поделиться
ICalculator myInterface = new JustSomeClass();
JustSomeClass myObject = (JustSomeClass) myInterface;

Теперь у вас есть оба «интерфейса» для работы с объектом.

Я тоже новичок в этом, но мне нравится думать об интерфейсах как о кнопках на пульте дистанционного управления. При использовании интерфейса ICalculator у вас есть доступ только к кнопкам (функциям), предусмотренным дизайнером интерфейса. При использовании ссылки на объект JustSomeClass у вас есть другой набор кнопок. Но оба они указывают на один и тот же объект.

Для этого есть много причин. Наиболее полезным для меня было общение между коллегами. Если они смогут согласовать интерфейс (кнопки, которые будут нажиматься), то один разработчик сможет работать над реализацией функциональности кнопки, а другой может написать код, который использует кнопки.

Надеюсь, это поможет.

0
ответ дан 30 November 2019 в 15:38
поделиться
Другие вопросы по тегам:

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