Мы начали использовать С# (.NET 3.0), и мне интересно, как вы, ребята, используете методы расширения? Когда вы их используете?
Кроме того, я был бы признателен, если бы вы также указали все темные предпосылки для их использования.
Мы начали использовать С# (.NET 3.0), и мне интересно, как вы, ребята, используете методы расширения? Когда вы их используете?
Кроме того, я был бы признателен, если бы вы также указали все темные предпосылки для их использования.
Методы расширения позволяют расширить существующие классы, не полагаясь на наследование или не изменить исходный код класса. Это означает, что если вы хотите добавить некоторые методы в существующий класс String, вы можете сделать это довольно легко. Вот пара правил, которые следует учитывать при принятии решения о том, следует ли использовать методы расширения:
Методы расширения не могут использоваться для переопределения существующих методов.
Метод расширения с тем же именем и сигнатурой, что и метод экземпляра, не будет называться
Концепция методов расширения не может применяться к полям, свойствам или событиям
Используйте методы расширения экономно.... чрезмерное использование может быть плохим!
Время для использования методов расширения:
Пример второй точки; у вас может быть метод расширения на IList<T>
(например, Sort
), который может быть написан полностью с использованием существующих членов IList<T>
... так зачем заставлять кого-нибудь писать что-нибудь? Это базовый блок LINQ и позволил Microsoft обеспечить гораздо больше функциональности, не нарушая ничего.
Время < не использовать методы расширения:
Я использую методы расширения, когда это имеет смысл. Если вы контролируете класс и его код, вам обычно не нужны методы расширения.
Если вы этого не сделаете, может быть полезным метод расширения.
Одно место, которое я часто использую методы расширения, - это перечисления [Flags]. Когда у вас есть перечисление на основе флага, существует довольно большое выражение, необходимое для определения того, имеет ли значение перечисления определенный набор флагов. И поэтому я строю следующий метод расширения всякий раз, когда я строю перечисление [Flags]:
[Flags]
public enum MyEnum
{
FlagA,
FlagB,
// etc.
}
public static class MyEnumExt
{
public static bool HasFlags(this MyEnum item, MyEnum query)
{
return ((item & query) == query);
}
}
Таким образом, мой код выглядит следующим образом:
MyEnum flags = MyEnum.FlagA;
if(flags.HasFlags(MyEnum.FlagA))
{
// handle FlagA
}
Вместо
MyEnum flags = MyEnum.FlagA;
if((flags & MyEnum.FlagA) == MyEnum.FlagA)
{
// handle FlagA
}
Эта ссылка http://geekswithblogs.net/BlackRabbitCoder/archive/2010/04/26/c-extension-methods---to-extend-or-not-to-extend.aspx дает хорошие рекомендации о том, когда использовать методы расширения, а когда нет.
Чтобы процитировать эту статью:
Хороший метод расширения должен:
- Применить к любому возможному экземпляру типа, который он расширяет.
- Упростить логику и улучшить читаемость/ремонтопригодность.
- Применить к конкретному типу или интерфейсу.
- быть изолированным в пространстве имен, чтобы он не загрязнял IntelliSense.
Честно говоря, я бы сказал, что легче сказать, когда это НЕ хорошая идея, тогда, когда это хорошая идея.
Я думаю, что основное преимущество методов расширения заключается в том, что они могут увеличить принятие вашего метода. Это связано с тем, что пользователю не нужно создавать экземпляр другого класса, чтобы использовать ваш метод, и intelisense будет рекламировать ваш метод, когда разработчик ищет методы для вашего класса. Это может быть важно, если вы пытаетесь заставить других разработчиков следовать новому стандарту в вашей компании.
При рассмотрении вопроса о том, следует ли создавать метод расширения, помните принципы SOLID.
S ingle Ответственность: - Вы почти всегда, по крайней мере, сгибаете принцип единой ответственности > с помощью метода расширения, потому что вы привязываетесь к тому, что уже есть > класс (который вы либо не контролируете, либо слишком боитесь касаться).
O ручка/принцип закрытия: - Методы расширения также не являются чрезмерными, что означает, что ваш метод не может быть "адекватно" открыт для расширения.
L принцип замены исков - Если у вас есть какая-то структура наследования, вы не сможете использовать методы расширения для вспомогательных типов.
I принцип сегрегации -Хотя вы можете "расширить" интерфейс, вы должны предоставить конкретную реализацию для этого расширения. Таким образом, вы не можете запрограммировать интерфейs > , который реализуется по-разному в другом контексте (например, Unit Test)
D принцип инверсии вершин - Если ваш код имеет какие-либо зависимости, как вы собираетесь раскрывать эти зависимости для заводов и модульных тестов (принцип инверсии зависимостей)?
Наконец, методы расширения - это просто статические методы, носящие новое платье. Таким образом, все трудности со статическими методами (например, безопасность потока, сборка мусора и т.д.) идут вместе с методами расширения при их реализации.
Итак, я долго и долго думал о написании метода в качестве расширения и пересмотреть с помощью factory и базового вспомогательного класса.
Если вы пишете метод расширения, сделайте его очень простым. Старайтесь избегать любых зависимостей (или передавать все ваши зависимости в качестве параметров). И будьте осторожны, как вы управляете памятью и блокируете ресурсы в многопоточной среде.