Як продовжити клас за допомогою методів розширення c #?


98

Чи можна застосувати методи розширення до класу?

Наприклад, продовжте DateTime, щоб включити метод Завтра (), до якого можна викликати:

DateTime.Tomorrow();

Я знаю, що можу використовувати

static DateTime Tomorrow(this Datetime value) { //... }

Або

public static MyClass {
  public static Tomorrow() { //... }
}

для аналогічного результату, але як я можу продовжити DateTime, щоб я міг викликати DateTime.Touorrow?

Відповіді:


70

Ви не можете додати методи до існуючого типу, якщо існуючий тип не позначений як частковий, ви можете додавати лише методи, які, схоже, є членами існуючого типу за допомогою методів розширення. Оскільки це так, ви не можете додавати статичні методи до самого типу, оскільки методи розширення використовують екземпляри цього типу.

Ніщо не заважає вам створити власний метод статичного помічника, як це:

static class DateTimeHelper
{
    public static DateTime Tomorrow
    {
        get { return DateTime.Now.AddDays(1); }
    }
}

Що б ви використовували так:

DateTime tomorrow = DateTimeHelper.Tomorrow;

6
да вуто? якщо воно не було реалізовано в протягом 6 місяців цього і Kumu відповідь «s прямо, це виглядає на насправді неповний!
Крегокс

4
@Cawas це не неповно, Ендрю показує, як це зробити зі статичним помічником, а не методом розширення (оскільки екземпляра немає).
Нік Н.

1
Ти маєш рацію, Нік. Я все ж віддаю перевагу методам розширення! ;)
Крегокс

2
Що про extensionmethod.net/csharp/datetime ? IMHO, кращі зразки для мінімізації кривої навчання - це реальні програми з повним вихідним кодом та хорошими зразками
Kiquenet,

3
Проблема цього коду полягає в тому, що він працює лише на DateTime.Now, а не на будь-якому об'єкті DateTime. Як корисну програму, ви можете використовувати її для визначення дня після деякого попереднього (або майбутнього) дня. Не кажучи вже про DateTime.Зараз визначається щоразу, коли ви його називаєте ...
MintGrowth

181

Використовуйте метод розширення .

Наприклад:

namespace ExtensionMethods
{
    public static class MyExtensionMethods
    {
        public static DateTime Tomorrow(this DateTime date)
        {
            return date.AddDays(1);
        }    
    }
}

Використання:

DateTime.Now.Tomorrow();

або

AnyObjectOfTypeDateTime.Tomorrow();

2
Shuggy відповідь «s також подрібнювати певне світло на подібні шляхи вирішення цього.
Крегокс

8
Не забудьте "використовувати ExtensionMethods;" для цього вгорі документа.
Люк Олдертон

чому я не можу зробити DateTime.Tomorrow ()?
lawphotog

Привіт lawphotog, для цього розширення потрібен об'єкт, тут DateTime - це структура, а не об’єкт.
Kumu

4
Як було сказано в попередніх коментарях (для мене це було недостатньо зрозуміло), ви НЕ зможете використовувати DateTime.Tomorrow()як методи розширення роботу лише над ІНСТАНЦІЯМИ класу та структури класу. Щоб "розширити" статичний метод на структурі класу, дотримуйтесь відповіді Ендрю або відповіді Шуггі .
Олексій

18

Методи розширення - це синтаксичний цукор для створення статичних методів, першим параметром яких є екземпляр типу T виглядати так, ніби вони були методом екземпляра на T.

Як така, користь значною мірою втрачається там, де ви робите «статичні методи розширення», оскільки вони служать для того, щоб заплутати читача коду навіть більше, ніж метод розширення (оскільки вони здаються повністю кваліфікованими, але насправді не визначені в цьому класі) без синтаксичного посилення (наприклад, можливість ланцюга дзвінків у вільному стилі в межах Linq, наприклад).

Оскільки вам доведеться все-таки приводити розширення до сфери використання з використанням, я б заперечував, що створити простіше і безпечніше:

public static class DateTimeUtils
{
    public static DateTime Tomorrow { get { ... } }
}

А потім використовуйте це у своєму коді за допомогою:

WriteLine("{0}", DateTimeUtils.Tomorrow)

11

Найближче до відповіді я можу додати метод розширення в System.Typeоб’єкт. Не красиво, але все ж цікаво.

public static class Foo
{
    public static void Bar()
    {
        var now = DateTime.Now;
        var tomorrow = typeof(DateTime).Tomorrow();
    }

    public static DateTime Tomorrow(this System.Type type)
    {
        if (type == typeof(DateTime)) {
            return DateTime.Now.AddDays(1);
        } else {
            throw new InvalidOperationException();
        }
    }
}

В іншому випадку, ІМО Ендрю та ShuggyCoUk мають кращу реалізацію.


Є проблеми з таким підходом. Набрати тип "typeof (...)" - це не зручно, і з intellisense ви побачите розширення кожного типу. І все-таки це цікавий підхід, про який я не думав, +1.
Meta-Knight

@ Meta-Knight Правда, тому особисто я віддаю перевагу відповіді інших. Моя відповідь мала б найближчий синтаксис до питання про ОП, але це не найкращий спосіб вирішити цю проблему.
Адріан Годонг

Typeможна замінити будь-яким іншим необхідним типом. Я ним користуюся, Fromі він прекрасно працює. тож я думаю, що ця відповідь є загальною, але правильною
Катя

3

Я зробив би те саме, що і Куму

namespace ExtensionMethods
{
    public static class MyExtensionMethods
    {
        public static DateTime Tomorrow(this DateTime date)
        {
           return date.AddDays(1);
        }    
    }
}

але назвіть це так, як це новий DateTime (). Завтра ();

Подумайте, що це робить більше, ніж DateTime.Now.Tomorrow ();


1
І ви упустили шанс написати це як коментар до відповіді Куму! : P
Крегокс

3

Вони забезпечують можливість розширення існуючих типів, додаючи нові методи без змін, необхідних для цього типу. Методи виклику з об'єктів розширеного типу в додатку з використанням синтаксису методу екземпляра відомі як "'розширення". Методи розширення не є членами примірника типу. Ключовим моментом, який слід пам’ятати, є те, що методи розширення, визначені як статичні методи, знаходяться в області застосування лише тоді, коли простір імен явно імпортується у ваш вихідний код програми за допомогою використання директиви. Незважаючи на те, що методи розширення визначені як статичні методи, вони все ще називаються за допомогою синтаксису екземпляра.

Перевірте повний приклад тут http://www.dotnetreaders.com/articles/Extension_methods_in_C-sharp.net,Methods_in_C_-sharp/201

Приклад:

class Extension
    {
        static void Main(string[] args)
        {
            string s = "sudhakar";
            Console.WriteLine(s.GetWordCount());
            Console.ReadLine();
        }

    }
    public static class MyMathExtension
    {

        public static int GetWordCount(this System.String mystring)
        {
            return mystring.Length;
        }
    }

3

Я шукав щось подібне - перелік обмежень для класів, які надають Методи розширення. Складно знайти стислий список, і ось тут:

  1. У вас не може бути нічого приватного чи захищеного - поля, методи тощо.

  2. Це повинен бути статичний клас, як у public static class....

  3. У класі можуть бути лише методи, і всі вони повинні бути загальнодоступними.

  4. У вас не може бути звичайних статичних методів - ті, що не містять цей аргумент, заборонені.

  5. Усі методи повинні розпочатися:

    загальнодоступна статична ReturnType MethodName (це класне ім'я _ це, ...)

Тож першим аргументом завжди є це посилання.

Це створюється неявною проблемою - якщо ви додасте методи, які вимагають блокування будь-якого типу, ви не можете реально надати його на рівні класу. Зазвичай ви надаєте приватний замок на рівні екземпляра, але додати приватні поля неможливо, залишаючи вам дуже незручні варіанти, наприклад, надаючи його як публічну статику для якогось поза класу тощо. Знаки мови C # мали певний поворот у дизайні для них .

Вирішення проблеми полягає у використанні класу Метод розширення як просто фасаду до звичайного класу, а всі статичні методи у вашому класі розширення просто викликають реальний клас, ймовірно, використовуючи Singleton .


2

На жаль, ви не можете цього зробити. Я вважаю, що це було б корисно. Більш природно набирати:

DateTime.Tomorrow

ніж:

DateTimeUtil.Tomorrow

З класом Util вам потрібно перевірити наявність статичного методу у двох різних класах, а не в одному.


1

Ми вдосконалили нашу відповідь з детальним поясненням. Тепер про спосіб розширення зрозуміти простіше

Спосіб розширення : це механізм, за допомогою якого ми можемо розширити поведінку існуючого класу, не використовуючи підкласифікацію, не змінюючи чи перекомпілюючи початковий клас чи структуру.

Ми можемо розширити наші власні класи, .net рамкові класи тощо.

Метод розширення - це фактично особливий вид статичного методу, який визначається в статичному класі.

Оскільки DateTimeклас вже взято вище, отже, ми не взяли цей клас для пояснення.

Нижче наведено приклад

// Це існуючий клас калькулятора, у якого є лише один метод (Додати)

public class Calculator 
{
    public double Add(double num1, double num2)
    {
        return num1 + num2;
    }

}

// Below is the extension class which have one extension method.  
public static class Extension
{
    // It is extension method and it's first parameter is a calculator class.It's behavior is going to extend. 
    public static double Division(this Calculator cal, double num1,double num2){
       return num1 / num2;
    }   
}

// We have tested the extension method below.        
class Program
{
    static void Main(string[] args)
    {
        Calculator cal = new Calculator();
        double add=cal.Add(10, 10);
        // It is a extension method in Calculator class.
        double add=cal.Division(100, 10)

    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.