Autofac and Decorator

0

Robiłem zgodnie z manualem przeczytałem kilka artykułów i nie znalazłem odpowiedzi.

Powinienem otrzymać 2 obiekty z dekoratorem.

Znajdzie się ktoś kto rzuci na to swoim okiem.?

using System;
using System.Collections.Generic;
using Autofac;
using System.Reflection;

namespace test
{
    public interface ICommand
    {
        string Execute();
    }

    public class SaveCommand : ICommand
    {
        public string Execute()
        {
            return "Saving the image...";
        }
    }

    public class OpenCommand : ICommand
    {
        public string Execute()
        {
            return "Opening an image...";
        }
    }

    public class ToolbarButton : ICommand
    {
        readonly ICommand _command;

        public ToolbarButton(ICommand inner)
        {
            _command = inner;
        }

        public string Execute()
        {
             return _command.Execute() + "DECORATOR";
        }
    }

    public class EditorWindow
    {
        readonly IEnumerable<ToolbarButton> _toolbarButtons;

        public EditorWindow(IEnumerable<ToolbarButton> toolbarButtons)
        {
            _toolbarButtons = toolbarButtons;
        }

        public void Show()
        {
            foreach (var tb in _toolbarButtons)
                Console.WriteLine(tb.Execute());
        }
    }

    class Program
    {
        static void Main()
        {
            var builder = new ContainerBuilder();
  

            builder.RegisterType<SaveCommand>().Named<ICommand>("command");
            builder.RegisterType<OpenCommand>().Named<ICommand>("command");
            builder.RegisterType<ToolbarButton>();
            builder.RegisterType<EditorWindow>();
            builder.RegisterDecorator<ICommand>(
                (c, inner) => new ToolbarButton(inner),
                fromKey: "command");

            using (var container = builder.Build())
            {
                var window = container.Resolve<EditorWindow>();
                window.Show();
            }

            Console.WriteLine("Done. Press any key.");
            Console.ReadKey(true);

            
        }
    }
}

0

Nie wiem czy dokładnie o to Ci chodzi. Jeżeli dobrze zrozumiałem to chcesz mieć w EditorWindow dwa ToolbarButton'y opakowujące Save i Open?

   class Program
    {
        static void Main()
        {
            var builder = new ContainerBuilder();

            builder.RegisterAdapter<ICommand, ToolbarButton>(cmd => new ToolbarButton(cmd));
            builder.RegisterType<EditorWindow>();

            builder.RegisterType<SaveCommand>().As<ICommand>();
            builder.RegisterType<OpenCommand>().As<ICommand>();

            builder.RegisterDecorator<ICommand>(
                (c, inner) => new ToolbarButton(inner),
                fromKey: "command");

            using (var container = builder.Build())
            {
                var window = container.Resolve<EditorWindow>();
                window.Show();
            }

            Console.WriteLine("Done. Press any key.");
            Console.ReadKey(true);

        }
    }
0

Działa, pomimo że,

builder.RegisterDecorator<ICommand>(
                (c, inner) => new ToolbarButton(inner),
                fromKey: "command");

można w tym momęcie wyrzucić.

Problem w tym że użyłeś funkcji która do tego nie służy, według manuala powinienem używać RegisterDecorator.

var builder = new ContainerBuilder();

// Register the services to be decorated. You have to
// name them rather than register them As<ICommandHandler>()
// so the *decorator* can be the As<ICommandHandler>() registration.
builder.RegisterType<SaveCommandHandler>()
       .Named<ICommandHandler>("handler");
builder.RegisterType<OpenCommandHandler>()
       .Named<ICommandHandler>("handler");

// Then register the decorator. The decorator uses the
// named registrations to get the items to wrap.
builder.RegisterDecorator<ICommandHandler>(
    (c, inner) => new CommandHandlerDecorator(inner),
    fromKey: "handler");

var container = builder.Build();

// The resolved set of commands will have two items
// in it, both of which will be wrapped in a CommandHandlerDecorator.
var handlers = container.Resolve<IEnumerable<ICommandHandler>>();

Tylko dlaczego to nie działa tak jak powinno

1

No faktycznie pomieszałem pojęcia. Autofac jest mi obcy, ale stwierdziłem, że się trochę douczę. Oczywiście metodą prób i błędów :)

Z tego co wyczytałem to rejestrując klasy, które mają być dekorowane najlepiej zrobić to przez nazwanie. W kodzie mamy dwie nazwane "command". Następnie rejestrujemy dekorator typu ToolbarButton dla wszystkich typów zarejestrowanych z nazwą "command".

Po drobnej zmianie w klasie EditorWindow Autofac domyśla się już poprawnie. Nadal możesz dodać inne komendy, które będą dekorowane jako ToolbarButton, wystarczy je odpowiednio nazwać.

Nie wiem czy to nie narusza Twoich innych założeń, ale wygląda, że teraz dekoruje i działa zgodnie z pierwotnym pomysłem?

using System;
using System.Collections.Generic;
using Autofac;

namespace test
{
    public interface ICommand
    {
        string Execute();
    }

    public class SaveCommand : ICommand
    {
        public string Execute()
        {
            return "Saving the image...";
        }
    }

    public class OpenCommand : ICommand
    {
        public string Execute()
        {
            return "Opening an image...";
        }
    }

    public class ToolbarButton : ICommand
    {
        readonly ICommand _command;

        public ToolbarButton(ICommand inner)
        {
            _command = inner;
        }

        public string Execute()
        {
            return _command.Execute() + " DECORATOR";
        }
    }

    public class EditorWindow
    {
        readonly IEnumerable<ICommand> _toolbarButtons;

        public EditorWindow(IEnumerable<ICommand> toolbarButtons)
        {
            _toolbarButtons = toolbarButtons;
        }

        public void Show()
        {
            foreach (var tb in _toolbarButtons)
                Console.WriteLine(tb.Execute());
        }
    }

    class Program
    {
        static void Main()
        {
            var builder = new ContainerBuilder();

            builder.RegisterType<EditorWindow>();

            builder.RegisterType<OpenCommand>().Named<ICommand>("command");
            builder.RegisterType<SaveCommand>().Named<ICommand>("command");
           
            builder.RegisterDecorator<ICommand>((c, inner) => new ToolbarButton(inner), fromKey: "command");

            using (var container = builder.Build())
            {
                var window = container.Resolve<EditorWindow>();
                window.Show();
            }

            Console.WriteLine("Done. Press any key.");
            Console.ReadKey(true);

        }
    }
}
0

Żeczywiście kiedy rejestruje typ

 builder.RegisterType<ToolbarButton>();

Nie powinienem używać RegisterDecorator

builder.RegisterDecorator<ICommand>((c, inner) => new ToolbarButton(inner), fromKey: "command");

Albo jedno albo drugie.

Trochę problematyczne są takie sytuacje ani syntax nic nie powie ani wyjątek nie zostanie wyrzucony.

Dzięki za pomoc. Nie ma jak to świeże oko.

1 użytkowników online, w tym zalogowanych: 0, gości: 1