Методы расширения

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

Фактически команды и расширения — это одно и тоже. В чём же заключается уникальность методов расширения, что им дали даже отдельное название? А дело в том, что они дают возможность добавить методы в существующие типы, не изменяя их. Это позволит нам писать дополнительные команды, которые будут вызываться через объект, а не как обычная функция.

Чтобы использовать такие методы, мы должны создать статический класс с любым названием. Далее писать методы в особом стиле, передавая в параметры ключевое слово this перед названием расширяемого класса:

public static class MyExtension {

    public static void setup( this Actor hActor ) {
        // hActor.XXXXX();
    }

}

Мы видим, что код расширения пишется так же, как и обычная команда. Единственное, чем они отличаются: это наличие упомянутого this. Такое описание позволяет нам использовать метод setup в объектах класса Actor:

Actor myActor = local();
myActor.setup();

Когда мы обращаемся через . к объекту myActor, то заметим, что в списке его команд будет присутствовать наша функция setup. При её вызове мы увидим, что там нет параметра this Actor hActor. На самом деле в этот параметр будет неявно передаваться объект myActor, а нам останется только указать оставшиеся параметры, если такие есть.

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

public static class MyExtension {

    public static void destroy_if_exist( this Actor hActor ) {
        Script.and( hActor.is_defined(), delegate { 
            hActor.remove_references().destroy(); 
        } );
    }
    
}

Тогда нам останется только использовать его в нужном месте:

public class MAIN : Thread {

    Actor ped;

    public override START( LabelJump label ) {
        //...
        //ped.create( ... );
        
        ped.destroy_if_exist(); // <--

        //...
    }

}

Поскольку класс с расширениями должен быть статическим, то мы не можем использовать базовые команды напрямую. Для решения этой проблемы нужно вызывать их через класс Script или любой другой, который наследует его (Thread, Mission, MissionCustom, External, Function и все производные от них классы).

Если таких команд много, то лучше подключить нужный класс как статическое пространство имён:

using GTA;
//using GTA.Core;
using static GTA.Core.Script; // <--
//using static GTA.Thread;
//using static GTA.Mission;
//using static GTA.MissionCustom;
//using static GTA.External;
//using static GTA.Function;

Last updated