tdd ioc container ninject contextual binding - c#

I need some help with using contextual binding with ninject
I Have something like this :
public interface ISound
{
String Sound();
}
public class Cat : Animal
{
private string category;
private ISound sound;
public Cat(ISound sound, int age, string name, string sex, string category)
: base(age, name, sex)
{
this.sound = sound;
this.category = category;
}
public class CatSound : ISound
{
public String Sound()
{
return "Meow";
}
}
and exactly the same Dog Sound who implemets Sound
and my bindingmodule:
public class BindingModule:NinjectModule
{
private readonly SelectorMode _typeofsound;
public new StandardKernel Kernel => ServiceLocator.Kernel;
public BindingModule(SelectorMode mode)
{
_typeofsound = mode;
}
public override void Load()
{
if (_typeofsound == SelectorMode.Dog)
{
Kernel.Bind<ISound>().To<DogSound>();
}
else if(_typeofsound==SelectorMode.Cat)
{
Kernel.Bind<ISound>().To<CatSound>();
}
else
{
Kernel.Bind<ISound>().To<HorseSound>();
}
}
public class SelectorMode
{
public static SelectorMode Cat;
public static SelectorMode Horse;
public static SelectorMode Dog;
}
}
and the test i'm trying to run
public class WhenBindingCat:GivenABindingModule
{
[TestMethod]
public void SouldBindItToCat()
{
// var kernel=new Ninject.StandardKernel(new )
var sut = new BindingModule(SelectorMode.Cat);
sut.Load();
}
and it don't know how i should assert here

Try something like this:
[TestMethod]
public void SouldBindItToCat()
{
var sut = new BindingModule(SelectorMode.Cat);
IKernel kernel = new StandardKernel(sut);
Assert.IsTrue(kernel.Get<ISound>() is Cat);
}
and
replace SelectorMode class by enum
public enum SelectorMode
{
Cat, Horse, Dog
}

Related

Decorator pattern in C#

I try to simulate the decorator pattern in C#.
So I have these classes:
public abstract class Car
{
// private string description;
public abstract string Descripton
{
get;
}
public abstract int Cost();
}
public abstract class CarDecorator : Car
{
protected Car _decorated;
//private string description;
public CarDecorator(Car decoratied)
{
this._decorated = decoratied;
}
public override string Descripton
{
get
{
return _decorated.Descripton;
}
}
public override int Cost()
{
return _decorated.Cost();
}
public class EnhancedAutoPilot : CarDecorator
{
public EnhancedAutoPilot(Car car):base(car)
{
this._decorated = car;
}
public override string Descripton
{
get
{
return _decorated.Descripton + ", Enhanced autopilot";
}
}
public override int Cost()
{
return _decorated.Cost() + 5000;
}
}
public class ModelXS:Car
{
protected Car _decorated;
public string Description = "Model XS";
public override string Descripton
{
get
{
return _decorated.Descripton;
}
}
public override int Cost()
{
return 5500;
}
}
public class ModelXXX : Car
{
protected Car _decorated;
public string Description = "ModelXXX";
public override string Descripton
{
get
{
return _decorated.Descripton;
}
}
public override int Cost()
{
return 73000;
}
}
public class RearFacingSeats:CarDecorator
{
public RearFacingSeats(Car car):base(car)
{
this._decorated = car;
}
public override string Descripton
{
get
{
return _decorated.Descripton + ", Rear Facing Seats ";
}
}
public override int Cost()
{
return _decorated.Cost() + 4000;
}
}
public class SmartAirSuspension: CarDecorator
{
public SmartAirSuspension(Car car):base(car)
{
this._decorated = car;
}
public override string Descripton
{
get
{
return _decorated.Descripton + ", Smart Air Suspension ";
}
}
public override int Cost()
{
return _decorated.Cost() + 2500;
}
}
class Program
{
static void Main(string[] args)
{
Car car = new RearFacingSeats(new SmartAirSuspension(new EnhancedAutoPilot()));
}
}
But then I get this error:
There is no argument given that corresponds to the required formal parameter 'car' of 'EnhancedAutoPilot.EnhancedAutoPilot(Car)'
Your Cars are wrong, they look like decorators but are not, in fact they are supposed to be just implementations of Cars. Like this one:
public class ModelXS : Car
{
public override string Descripton
{
get
{
return "Model XS";
}
}
public override int Cost()
{
return 5500;
}
}
After that you can call the constructors like in #Richard 's answer and you are golden.
and you can ditch
public EnhancedAutoPilot(Car car):base(car)
{
this._decorated = car; // <<-- this lines
}
because you do that assignment in the base constructor of the CarDecorator class already.
You're using new EnhancedAutoPilot() constructor without parameters and it requires a Car parameter in your contructor signature.
public EnhancedAutoPilot(Car car):base(car)
Another issue i see is that you have _decorated in your Car class. The decorated object should only be in the Decorator classes.
So i would modify your car classes this way :
public class ModelXXX : Car
{
public override string Descripton => "ModelXXX";
public override int Cost()
{
return 73000;
}
}
public class ModelXS : Car
{
public override string Descripton => "Model XS";
public override int Cost()
{
return 5500;
}
}
And main would look like this :
static void Main(string[] args)
{
Car car = new ModelXXX();
car = new EnhancedAutoPilot(car);
car = new SmartAirSuspension(car);
car = new RearFacingSeats(car);
Console.Writeline(car.Descripton);
}
The error is telling you that you are not passing a value to the EnhancedAutoPilot() contstructor. All of your decorators require a Car instance be passed, thus you must instantiate a car first, before calling your decorators.
It looks like ModelXS and ModelXXX are types of cars, so the Program class should be:
class Program
{
static void Main(string[] args)
{
Car decoratedCar =
new RearFacingSeats(
new SmartAirSuspension(
new EnhancedAutoPilot(
new ModelXS())));
}
}

how to resolve a type safe collection in the constructor?

I have this object structure
public interface IHandler<in TMessage>
{
void HandleMessage(TMessage messageType);
}
public class MessageType1
{
}
public class MessageType2
{
}
public class HandlerMessageType1 : IHandler<MessageType1>
{
public void HandleMessage(T messageType)
{
}
}
public class HandlerMessageType2 : IHandler<MessageType2>
{
public void HandleMessage(T messageType)
{
}
}
and the registration
container.Collection.Register(typeof(IHandler<>), new[]
{
typeof(HandlerMessageType1),
typeof(HandlerMessageType2)
});
how the constructor of the class where this is injected should look like?
public class ClientClass
{
public ClientClass(IEnumerable<IHandler<>> handlers)
{
}
}
like this doesn't work... how the signature of the client class constructor should look like?
this was edited to improve the example.
tkx in advance
Paulo Aboim Pinto
I Know if I understood, but with unity you can have:
public class Handler1 : IHandler
{
public void HandlerType()
{
Console.WriteLine("Handler1");
}
}
public class Handler2 : IHandler
{
public void HandlerType()
{
Console.WriteLine("Handler2");
}
}
public interface IHandler
{
void HandlerType();
}
Unity configuration
public static class DependencyConfiguration
{
public static UnityContainer Config()
{
var unity = new UnityContainer();
unity.RegisterType<IHandler, Handler1>("Handler1");
unity.RegisterType<IHandler, Handler2>("Handler2");
unity.RegisterType<IEnumerable<IHandler>>();
return unity;
}
}
A class to resolve:
public class ListOfTypes
{
private List<IHandler> handlers;
public ListOfTypes(IEnumerable<IHandler> handlers)
{
this.handlers = handlers.ToList();
}
public void PrintHandlers()
{
handlers.ForEach(_ => _.HandlerType());
}
}
The program:
static void Main(string[] args)
{
Console.WriteLine("Resolve sample");
var unity = DependencyConfiguration.Config();
var lstOfTypes = unity.Resolve<ListOfTypes>();
lstOfTypes.PrintHandlers();
Console.ReadLine();
}
Result:

Generics cannot explicitly convert type

For background I mainly program in Java and am trying to work with/learn generics in a C# project and got stuck.
Here is my problem. From the main method you can see I am trying to set the soldiers task, but I'm getting the error,
cannot convert from 'TaskHeal' to 'TaskBase<SoldierBase>'
It seems that this cast should work as TaskHeal is a child of TaskBase, but it doesn't. Here is my complete code:
public class Main {
static void main(string[] args) {
SoldierMedic myMedic = new SoldierMedic();
myMedic.setTask(new TaskHeal(myMedic)); // Problem!
}
}
public class SoldierBase {
private TaskBase<SoldierBase> currentTask;
public int status;
public void setTask(TaskBase<SoldierBase> newTask) {
this.currentTask = newTask;
}
}
public class SoldierMedic : SoldierBase {
public int healRate = 45;
}
public abstract class TaskBase<T> where T : SoldierBase {
protected T soldier;
public TaskBase(T unit) {
this.soldier = unit;
this.soldier.status = 1;
}
public abstract void preformTask();
}
public class TaskHeal : TaskBase<SoldierMedic> {
public TaskHeal(SoldierMedic unit) : base(unit) { }
public override void preformTask() {
this.soldier.healRate++;
}
}
If you don't mind having an additional base, non-generic class for TaskBase and SoldierBase, you could do this:
class Program
{
static void Main(string[] args)
{
var myMedic = new SoldierMedic();
myMedic.setTask(new TaskHeal(myMedic)); // Problem!
}
}
public class SoldierBase
{
public int status;
}
public class SoldierBase<T> : SoldierBase where T : SoldierBase
{
private TaskBase currentTask;
public void setTask(TaskBase newTask)
{
this.currentTask = newTask;
}
}
public class SoldierMedic : SoldierBase<SoldierMedic>
{
public int healRate = 45;
}
public abstract class TaskBase
{
}
public abstract class TaskBase<T> : TaskBase where T : SoldierBase<T>
{
protected T soldier;
public TaskBase(T unit)
{
this.soldier = unit;
this.soldier.status = 1;
}
public abstract void preformTask();
}
public class TaskHeal : TaskBase<SoldierMedic>
{
public TaskHeal(SoldierMedic unit) : base(unit) { }
public override void preformTask()
{
this.soldier.healRate++;
}
}
If you want this to look more like c# (using properties, proper access modifiers and casing), you'd do something like this:
class Program
{
static void Main(string[] args)
{
var myMedic = new SoldierMedic();
myMedic.CurrentTask = new TaskHeal(myMedic); // Problem!
}
}
public class SoldierBase
{
public int Status { get; set; }
}
public class SoldierBase<T> : SoldierBase where T : SoldierBase
{
public TaskBase CurrentTask { get; set; }
}
public class SoldierMedic : SoldierBase<SoldierMedic>
{
public int HealRate { get; set; } = 45;
}
public abstract class TaskBase
{
}
public abstract class TaskBase<T> : TaskBase where T : SoldierBase<T>
{
protected T Soldier;
public TaskBase(T unit)
{
Soldier = unit;
Soldier.Status = 1;
}
public abstract void PerformTask();
}
public class TaskHeal : TaskBase<SoldierMedic>
{
public TaskHeal(SoldierMedic unit) : base(unit) { }
public override void PerformTask()
{
Soldier.HealRate++;
}
}

How to code a good Offline-Online Dispatcher

Let's assume that I have this scenario: I have got 2 repositories of information, and I want to access both, but it would be nice to leave the task of deciding which repo to use to common class.
The goal is to accomplish this with something similar to the code I've wrote below, but this sounds pretty bad:
where TOnline : class
where TOffline : class
where TContract : class
Sure I can ommit that, but bassically what I'm asking is what to do in order to stop using reflection and go typed. Maybe any design-pattern recomendation?
Code (if you copy/paste this on a console app replacing the Program class you should be able to run the example)
using CustomerDispatcher = DispatcherProxy<CustomerOnline, CustomerOffline, ICustomer>;
public interface ICustomer
{
string Get(int id);
}
public class CustomerOnline : ICustomer
{
public string Get(int id)
{
// Get From intranet DB
return "From DB";
}
}
public class CustomerOffline : ICustomer
{
public string Get(int id)
{
// Get From local storage
return "From local storage";
}
}
public class DispatcherProxy<TOnline, TOffline, TContract>
where TOnline : class
where TOffline : class
where TContract : class
{
public TContract Instance { get; set; }
public bool IsConnected { get; set; }
public DispatcherProxy()
{
// Asume that I check if it's connected or not
if (this.IsConnected)
this.Instance = (TContract)Activator.CreateInstance(typeof(TOnline));
else
this.Instance = (TContract)Activator.CreateInstance(typeof(TOffline));
}
}
class Program
{
static void Main(string[] args)
{
var customerDispatcher = new CustomerDispatcher();
Console.WriteLine("Result: " + customerDispatcher.Instance.Get(1));
Console.Read();
}
}
Thanks in advance!
You can add the new() constraint:
public class DispatcherProxy<TOnline, TOffline, TContract>
where TOnline : class, new()
where TOffline : class, new()
where TContract : class //isn't TContract an interface?
{
public TContract Instance { get; set; }
public bool IsConnected { get; set; }
public DispatcherProxy()
{
// Asume that I check if it's connected or not
if (this.IsConnected)
this.Instance = new TOnline() as TContract;
else
this.Instance = new TOffline() as TContract;
}
}
In case any of you are interested, I had to change the way I did this because it was checking connection at Constructor Level, and I needed that check at Operation Level.
using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
namespace ConsoleApplication1
{
public enum ConnectionStatus
{
Online,
Offline,
System // System checks connectivity
}
public static class Connectivity
{
private static ConnectionStatus ConnectionStatus = ConnectionStatus.Offline;
public static void ForceConnectionStatus(ConnectionStatus connectionStatus)
{
ConnectionStatus = connectionStatus;
}
public static bool IsConnected()
{
switch (ConnectionStatus)
{
case ConnectionStatus.Online:
return true;
case ConnectionStatus.Offline:
return false;
case ConnectionStatus.System:
return CheckConnection();
}
return false;
}
private static bool CheckConnection()
{
return true;
}
}
public class Unity
{
public static IUnityContainer Container;
public static void Initialize()
{
Container = new UnityContainer();
Container.AddNewExtension<Interception>();
Container.RegisterType<ILogger, OnlineLogger>();
Container.Configure<Interception>().SetInterceptorFor<ILogger>(new InterfaceInterceptor());
}
}
class Program
{
static void Main(string[] args)
{
Unity.Initialize();
var r = new Router<ILogger, OnlineLogger, OnlineLogger>();
Connectivity.ForceConnectionStatus(ConnectionStatus.Offline);
Console.WriteLine("Calling Online, will attend offline: ");
r.Logger.Write("Used offline.");
Connectivity.ForceConnectionStatus(ConnectionStatus.Online);
Console.WriteLine("Calling Online, will attend online: ");
r.Logger.Write("Used Online. Clap Clap Clap.");
Console.ReadKey();
}
}
public class Router<TContract, TOnline, TOffline>
where TOnline : TContract
where TOffline : TContract
{
public TContract Logger;
public Router()
{
Logger = Unity.Container.Resolve<TContract>();
}
}
public interface IOnline
{
IOffline Offline { get; set; }
}
public interface IOffline
{
}
public interface ILogger
{
[Test()]
void Write(string message);
}
public class OnlineLogger : ILogger, IOnline
{
public IOffline Offline { get; set; }
public OnlineLogger()
{
this.Offline = new OfflineLogger();
}
public void Write(string message)
{
Console.WriteLine("Online Logger: " + message);
}
}
public class OfflineLogger : ILogger, IOffline
{
public IOnline Online { get; set; }
public void Write(string message)
{
Console.WriteLine("Offline Logger: " + message);
}
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
public class TestAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new TestHandler();
}
}
public class TestHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
Console.WriteLine("It's been intercepted.");
if (!Connectivity.IsConnected() && input.Target is IOnline)
{
Console.WriteLine("It's been canceled.");
var offline = ((input.Target as IOnline).Offline);
if (offline == null)
throw new Exception("Online class did not initialized Offline Dispatcher.");
var offlineResult = input.MethodBase.Invoke(offline, this.GetObjects(input.Inputs));
return input.CreateMethodReturn(offlineResult, this.GetObjects(input.Inputs));
}
return getNext()(input, getNext);
}
private object[] GetObjects(IParameterCollection parameterCollection)
{
var parameters = new object[parameterCollection.Count];
int i = 0;
foreach (var parameter in parameterCollection)
{
parameters[i] = parameter;
i++;
}
return parameters;
}
}
}

How to StructureMap configuration?

On AppEngine "Franch" and "English" as a dependency injection what do I do?
class Program
{
static void Main(string[] args)
{
IContainer container = ConfigureDependencies();
IAppEngine appEngine = container.GetInstance<IAppEngine>();
IGeeter g1 = container.GetInstance<IGeeter>("Franch");
IGeeter g2 = container.GetInstance<IGeeter>("English");
appEngine.Run();
}
private static IContainer ConfigureDependencies()
{
return new Container(x =>
{
x.For<IGeeter>().Add<FrenchGreeter>().Named("Franch");
x.For<IGeeter>().Add<EnglishGreeter>().Named("English");
x.For<IAppEngine>().Use<AppEngine>();
x.For<IGeeter>().Use<EnglishGreeter>();
x.For<IOutputDisplay>().Use<ConsoleOutputDisplay>();
});
}
}
public interface IAppEngine
{
void Run();
}
public interface IGeeter
{
string GetGreeting();
}
public interface IOutputDisplay
{
void Show(string message);
}
public class AppEngine : IAppEngine
{
private readonly IGeeter english;
private readonly IGeeter franch;
private readonly IOutputDisplay outputDisplay;
public AppEngine(IGeeter english,IGeeter franch, IOutputDisplay outputDisplay)
{
this.english = english;
this.franch = franch;
this.outputDisplay = outputDisplay;
}
public void Run()
{
outputDisplay.Show(greeter.GetGreeting());
}
}
public class EnglishGreeter : IGeeter
{
public string GetGreeting()
{
return "Hello";
}
}
public class FrenchGreeter : IGeeter
{
public string GetGreeting()
{
return "Bonjour";
}
}
As the contract for FrenchGreeter and EnglishGreeter is the same, StructureMap will not know which to use. For each wireing it uses only one instance per contract. Try something like this:
For<IGreeter>().Use<FrenchGreeter>().Named("French");
For<IGreeter>().Use<EnglishGreeter>().Named("English");
For<IAppEngine>().Use<AppEngine>()
.Ctor<IGreeter>("French").Is(x => x.TheInstanceNamed("French"))
.Ctor<IGreeter>("English").Is(x => x.TheInstanceNamed("English"));

Categories

Resources