Search

Categories

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Send mail to the author(s) E-mail

# Friday, 18 May 2012
( Factory | JonSkeet | TekPub )

Taking the manually done dependency injection and using a factory now (then go away from factory to home grown  IoC)

//is this unneeded complexity if its a smaller app?  Actually this is a Factory
    //jon recommends if can keep in main method, then keep manual DI.
    class Injector
    {
        //getting ugly as can be literally 100's of dependencies
        public IClock CreateClock()
        {
            //a singleton
            return SystemClock.Instance;
        }

        public Licence CreateLicence()
        {
            return new Licence(Instant.UnixEpoch, CreateClock());
        }

        public DateTimeZone CreateTimeZone()
        {
            return DateTimeZone.GetSystemDefault();
        }

        public CalendarSystem CreateCalendarSystem()
        {
            return CalendarSystem.Iso;
        }

        public Diary CreateDiary()
        {
            return new Diary(CreateClock(),  CreateCalendarSystem(), CreateTimeZone());
        }

        public DiaryPresenter CreateDiaryPresenter()
        {
            return new DiaryPresenter(CreateDiary(), CreateLicence());
        }
    }

 

and then:

static void Main()
        {
            // newing up the factory
            Injector injector = new Injector();
            var presenter = injector.CreateDiaryPresenter();
            presenter.Start();
        }

outtake to video 5..outtake…IoC.  Basically wanting to make things more generic:

structuremap, ninject, autofac, Unity are IoC

eg in an MVC app I  http://www.programgood.net/2011/09/20/VidPub1SettingUpSolution.aspx:

“Every time you see a request for ILogger interface in a controller, return a new NLogger class”

kernel.Bind<ILogger>().To<NLogger>();
[TestFixture]
public class Program
{
    [Test]
    public void MainTest()
    {
        //manually setting up the dependencies
        IClock clock = SystemClock.Instance;
        Diary diary = new Diary(clock, CalendarSystem.Iso, DateTimeZone.GetSystemDefault());
        //licence expired in 1970, and current time is systemclock time
        Licence licence = new Licence(Instant.UnixEpoch, clock);
        var presenter = new DiaryPresenter(diary, licence);
        presenter.Start();

        //IoC
        //Injector injector = new Injector();
        //injector.Bind<IClock, SystemClock>();
        //injector.Bind<DateTimeZone>(DateTimeZone.GetSystemDefault());
        //injector.Bind<Instant>(Instant.FromUtc(2000,1,1,0,0,0));
        //injector.Bind<CalendarSystem>(CalendarSystem.Iso);

        ////you've got all these things.. now do stuff please
        //var presenter = injector.Resolve<DiaryPresenter>();
        //presenter.Start();

        
    }
}

class DiaryPresenter
{
    private readonly Diary diary;
    private readonly Licence licence;

    public DiaryPresenter(Diary diary, Licence licence)
    {
        this.diary = diary;
        this.licence = licence;
    }

    public void Start()
    {
        Console.WriteLine("Today is {0}", diary.FormatToday());
        Console.WriteLine("Licence expired? {0}", licence.HasExpired);
    }
}

class Licence
{
    //fields
    private readonly Instant expirey;
    private readonly IClock clock;

    public Licence(Instant expirey, IClock clock)
    {
        //variables or local variables
        this.expirey = expirey;
        this.clock = clock;
    }

    //property
    public bool HasExpired
    {
        get { return clock.Now >= expirey; }
    }
}

//calendaring application which will want to know what time it is too!
class Diary
{
    private readonly LocalDatePattern outputPattern = LocalDatePattern.CreateWithInvariantInfo("yyyy-MM-dd");
    //fields
    private readonly IClock clock;
    private readonly CalendarSystem calendar;
    private readonly DateTimeZone timeZone;

    //by demanding the dependencies in the constructor, classes are more flexible
    //especially if they are interfacess
    public Diary(IClock clock, CalendarSystem calendar, DateTimeZone timeZone)
    {
        this.clock = clock;
        this.calendar = calendar;
        this.timeZone = timeZone;
    }

    public string FormatToday()
    {
        //in system default timezone, and system default calendar
        //DateTime dateTime = DateTime.Today;
        LocalDate date = clock.Now.InZone(timeZone, calendar).LocalDateTime.Date;
        if (date.Month == 4)
        {  //ncrunch showing black here - so tests are not covering this codepath
            return "April fool";
        }
        return outputPattern.Format(date);
    }
}

A working version of the code with manual DI.

class Program
    {
        static void Main(string[] args)
        {
            //manually setting up the dependencies
            IClock clock = SystemClock.Instance;
            Diary diary = new Diary(clock, CalendarSystem.Iso, DateTimeZone.GetSystemDefault());
            //licence expired in 1970, and current time is systemclock time
            Licence licence = new Licence(Instant.UnixEpoch, clock);
            var presenter = new DiaryPresenter(diary, licence);
            presenter.Start();


            Console.WriteLine("Type in 1 for good licence, 2 for expired");
            string userInput = Console.ReadLine();
            if (userInput == "1")
            {
                //really need public properties on licence to reset it rather than instantiating a new one!
                licence = new Licence(Instant.FromUtc(2020,1,1,0,0,0), clock);
                presenter = new DiaryPresenter(diary, licence);
            }
            Console.WriteLine("License expiredx: {0}", licence.HasExpired);
            Console.ReadLine();
        }
    }

Made a new console project referencing the class project.  Proves that it does work as a real application and not just in test.

class Injector
{
    //going to be able to bind by instance and by type
    //where TConcrete derives from TKey
    //TKey is going to be what we provide

    //from type to a way of getting to an instance of that type
    private Dictionary<Type,Func<object>> providers = new Dictionary<Type, Func<object>>();

    //eg whenever you want IClock, use the SystemClock type
    public void Bind <TKey, TConcrete>() where TConcrete : TKey
    {
        //where we're
        providers[typeof(TKey)] = () => ResolveByType(typeof(TConcrete));
    }

    private object ResolveByType(Type type)
    {
        Console.WriteLine("Resolving...{0}", type);
        //assume we're got a single constructor in the type we're passing in
        var constructor = type.GetConstructors().SingleOrDefault();
        //if we don't have a constructor then maybe a static method
        if (constructor != null)
        {
            //want to invoke the constructor, but need to resolve all of its dependencies
            //eg when we ask for a diary, get me a clock, get me a calendar, get me a timezone
            var arguments = constructor.GetParameters()
                                       .Select(parameterInfo => Resolve(parameterInfo.ParameterType))
                                       .ToArray();
            return constructor.Invoke(arguments);
        }
        //Instance is a property on system clock
        //we're trying to find something on systemclock... however it was a field, thats why GetProperty wasn't returning it.
        //var instanceProperty = type.GetProperty("Instance", BindingFlags.Public | BindingFlags.Static);
        var instanceField = type.GetField("Instance");
        return instanceField.GetValue(null);
    }

    public void Bind<T>(T instance)
    {
        //returns the instance
        providers[typeof(T)] = () => instance;
    }

    internal TKey Resolve<TKey>()
    {
        return (TKey)Resolve(typeof(TKey));
    }

    //how do we resolve something?
    internal object Resolve(Type type)
    {
        Func<object> provider;

        if (providers.TryGetValue(type, out provider))
        {
            return provider();
        }
        return ResolveByType(type);
    }
}

need to come back to this and understand**

| | #