Альтернатива вызову абстрактного метода в конструкторе базового класса - PullRequest
0 голосов
/ 16 ноября 2018

Моя проблема заключается в следующем:

У меня есть базовый класс

public abstract class ViewModelBase 

который содержит абстрактный метод "RegisterCommands"

protected abstract void RegisterCommands();

Все мои классы Derived должны, очевидно, реализовывать этот метод, например, мой LoginViewModel имеет

protected override void RegisterCommands()
{
    LoginCommand?
        .Configure(
            execute: (msg) => { Login(User); },
            canExecute: (x) => { return CanLogin(); }
            );
}

и вызывать его, когда создается экземпляр класса, но я не хочу вызывать этот метод в каждом конструкторе производного класса (если у меня есть 100 производных классов, я должен вызывать RegisterCommand 100 раз).

Обычным решением является вызов RegisterCommand в конструкторе базового класса

protected abstract void RegisterCommands();

public ViewModelBase()
{
    RegisterCommands();
}

и это обычно работает (даже если я не знаю, хорошая ли это практика), но ... но ...

в моем сценарии во всех методах RegisterCommands я использую свои объекты ICustomCommand, которые инициализируются в конструкторе производного класса с внедрением зависимости

public class LoginViewModel : ViewModelBase
{

    private ICustomCommand _loginCommand;

    public ICustomCommand LoginCommand
    {
        get
        {
            return _loginCommand;
        }
        set
        {
            _loginCommand = value;
        }
    }

    public LoginViewModel(ICustomCommand loginCommand)
    {
        _loginCommand = loginCommand;
    }

    protected override void RegisterCommands()
    {
        LoginCommand?
            .Configure(
                execute: (msg) => { Login(User); },
                canExecute: (x) => { return CanLogin(); }
                );
    }

Итак, поскольку конструктор базового класса вызывается перед конструктором производного класса, я не могу вызвать RegisterCommands () в конструкторе базового класса (потому что мои ICustomCommands еще не инициализированы в производном классе, поэтому RegisterCommands () пытается использовать мой ICustomCommand, который все еще ноль).

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

спасибо за ответ

UPDATE:

Как я уже сказал, RegisterCommands () является множественным, потому что каждый производный класс может иметь N объектов ICustomCommand

Так что я могу иметь

LoginCommand для моей LoginViewModel

SaveCommand, DeleteCommand для другой ViewModel

и т.д.

Одним из решений, которое я думаю сейчас, является удаление инициализации ICustomCommand из конструктора и ее разрешение «на лету» в свойстве геттера через статический класс Resolver, что-то вроде этого

public ICustomCommand LoginCommand
{
    get
    {
        if(_loginCommand == null)
            MyStaticResolver.Resolve<ICustomCommand>();
        return _loginCommand;

Но я все еще не убежден

1 Ответ

0 голосов
/ 16 ноября 2018

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

public abstract class ViewModelBase
{
    public ViewModelBase(params ICustomCommand[] commands)
    {
        _commands = commands;            
        RegisterCommands();
    }

    private IEnumerable<ICustomCommand> _commands;

    protected abstract void RegisterCommands();

    //This method gets you the commands
    protected T GetCommand<T>() where T : ICustomCommand
    {
        var command = _commands.FirstOrDefault(c => typeof(T).IsAssignableFrom(c.GetType()));
        return (T)command ;
    }
}

public class LoginViewModel : ViewModelBase
{
    public LoginViewModel(ILoginCommand command):base(command)
    {

    }

    protected override void RegisterCommands()
    {
        //Get the command from the base class
        var command = GetCommand<ILoginCommand>();
        command?
        .Configure(
            execute: (msg) => { Login(User); },
            canExecute: (x) => { return CanLogin(); }
            );
    }
}

public class LoginCommand : ILoginCommand
{
}

public interface ILoginCommand : ICustomCommand
{
}
...