2 people like it.

Parametric Dependency Injection

This is a simple IoC implementation that allows registration with optional parametrization.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
36: 
37: 
38: 
39: 
40: 
41: 
42: 
43: 
44: 
45: 
46: 
47: 
48: 
49: 
50: 
51: 
52: 
53: 
54: 
55: 
56: 
57: 
58: 
59: 
60: 
61: 
62: 
63: 
64: 
65: 
66: 
67: 
68: 
69: 
70: 
71: 
72: 
73: 
74: 
75: 
76: 
type Mode = Singleton | Factory

type private DependencyContainer<'T> () =
    // this implementation does not account for thread safety
    // a good way to go would be to wrap the container map
    // in an atom structure like the one in http://fssnip.net/bw
    static let container : Map<string option, unit -> 'T> ref = ref Map.empty

    static let t = typeof<'T>

    static let morph mode (f : unit -> 'T) =
        match mode with
        | Singleton ->
            let singleton = lazy(f ())
            fun () -> singleton.Value
        | Factory -> f

    static member Register (mode, factory : unit -> 'T, param) =
        if (!container).ContainsKey param then
            match param with
            | None -> failwithf "IoC : instance of type %s has already been registered" t.Name
            | Some param -> failwithf "IoC : instance of type %s with parameter \"%s\" has already been registered" t.Name param
        else container := (!container).Add(param, morph mode factory)
            

    static member IsRegistered param = (!container).ContainsKey param

    static member TryResolve param =
        match (!container).TryFind param with
        | None -> None
        | Some f ->
            try Some <| f ()
            with e -> 
                match param with
                | None -> failwithf "IoC : factory method for type %s has thrown an exception:\n %s" t.Name <| e.ToString()
                | Some param -> 
                    failwithf "IoC : factory method for type %s with parameter \"%s\" has thrown an exception:\n %s" t.Name param <| e.ToString()

    static member Resolve param =
        match DependencyContainer<'T>.TryResolve param with
        | Some v -> v
        | None ->
            match param with
            | None -> failwithf "IoC : no instace of type %s has been registered" t.Name
            | Some param -> failwithf "IoC : no instance of type %s with parameter \"%s\" has been registered" t.Name param


type IoC =
    static member Register<'T> (mode, factory, ?param) = DependencyContainer<'T>.Register(mode, factory, param)
    static member RegisterValue<'T> (value, ?param) = DependencyContainer<'T>.Register(Factory, (fun () -> value), param)
    static member TryResolve<'T> ?param = DependencyContainer<'T>.TryResolve param
    static member Resolve<'T> ?param = DependencyContainer<'T>.Resolve param
    static member IsRegistered<'T> ?param = DependencyContainer<'T>.IsRegistered param


// example

type IAnimal =
    abstract Name : string

type Cat(name) =
    member __.Purr() = printfn "purrr"
    interface IAnimal with
        member __.Name = name
        
IoC.Register<IAnimal>(Singleton, fun () -> new Cat("Mr. Bungle") :> IAnimal)
IoC.RegisterValue<IAnimal>( { new IAnimal with member __.Name = "Eirik" }, "me")

let cat = IoC.Resolve<IAnimal>() :?> Cat
let me = IoC.Resolve<IAnimal> "me"

cat.Purr()
me.Name

IoC.RegisterValue(42, "magic number")
IoC.Resolve<int> "magic number"
union case Mode.Singleton: Mode
union case Mode.Factory: Mode
Multiple items
type private DependencyContainer<'T> =
  new : unit -> DependencyContainer<'T>
  static member IsRegistered : param:string option -> bool
  static member Register : mode:Mode * factory:(unit -> 'T) * param:string option -> unit
  static member Resolve : param:string option -> 'T
  static member TryResolve : param:string option -> 'T option

Full name: Script.DependencyContainer<_>

--------------------
private new : unit -> DependencyContainer<'T>
val container : Map<string option,(unit -> 'T)> ref
Multiple items
module Map

from Microsoft.FSharp.Collections

--------------------
type Map<'Key,'Value (requires comparison)> =
  interface IEnumerable
  interface IComparable
  interface IEnumerable<KeyValuePair<'Key,'Value>>
  interface ICollection<KeyValuePair<'Key,'Value>>
  interface IDictionary<'Key,'Value>
  new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
  member Add : key:'Key * value:'Value -> Map<'Key,'Value>
  member ContainsKey : key:'Key -> bool
  override Equals : obj -> bool
  member Remove : key:'Key -> Map<'Key,'Value>
  ...

Full name: Microsoft.FSharp.Collections.Map<_,_>

--------------------
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
type 'T option = Option<'T>

Full name: Microsoft.FSharp.Core.option<_>
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
Multiple items
val ref : value:'T -> 'T ref

Full name: Microsoft.FSharp.Core.Operators.ref

--------------------
type 'T ref = Ref<'T>

Full name: Microsoft.FSharp.Core.ref<_>
val empty<'Key,'T (requires comparison)> : Map<'Key,'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.empty
val t : System.Type
val typeof<'T> : System.Type

Full name: Microsoft.FSharp.Core.Operators.typeof
val morph : (Mode -> (unit -> 'T) -> unit -> 'T)
val mode : Mode
val f : (unit -> 'T)
val singleton : Lazy<'T>
property System.Lazy.Value: 'T
static member private DependencyContainer.Register : mode:Mode * factory:(unit -> 'T) * param:string option -> unit

Full name: Script.DependencyContainer`1.Register
val factory : (unit -> 'T)
val param : string option
union case Option.None: Option<'T>
val failwithf : format:Printf.StringFormat<'T,'Result> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.failwithf
property System.Reflection.MemberInfo.Name: string
union case Option.Some: Value: 'T -> Option<'T>
val param : string
static member private DependencyContainer.IsRegistered : param:string option -> bool

Full name: Script.DependencyContainer`1.IsRegistered
static member private DependencyContainer.TryResolve : param:string option -> 'T option

Full name: Script.DependencyContainer`1.TryResolve
val e : exn
System.Exception.ToString() : string
static member private DependencyContainer.Resolve : param:string option -> 'T

Full name: Script.DependencyContainer`1.Resolve
val v : 'T
type IoC =
  static member IsRegistered : ?param:string -> bool
  static member Register : mode:Mode * factory:(unit -> 'T) * ?param:string -> unit
  static member RegisterValue : value:'T * ?param:string -> unit
  static member Resolve : ?param:string -> 'T
  static member TryResolve : ?param:string -> 'T option

Full name: Script.IoC
static member IoC.Register : mode:Mode * factory:(unit -> 'T) * ?param:string -> unit

Full name: Script.IoC.Register
static member IoC.RegisterValue : value:'T * ?param:string -> unit

Full name: Script.IoC.RegisterValue
val value : 'T
static member IoC.TryResolve : ?param:string -> 'T option

Full name: Script.IoC.TryResolve
static member IoC.Resolve : ?param:string -> 'T

Full name: Script.IoC.Resolve
static member IoC.IsRegistered : ?param:string -> bool

Full name: Script.IoC.IsRegistered
type IAnimal =
  interface
    abstract member Name : string
  end

Full name: Script.IAnimal
abstract member IAnimal.Name : string

Full name: Script.IAnimal.Name
Multiple items
type Cat =
  interface IAnimal
  new : name:string -> Cat
  member Purr : unit -> unit

Full name: Script.Cat

--------------------
new : name:string -> Cat
val name : string
member Cat.Purr : unit -> unit

Full name: Script.Cat.Purr
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val __ : Cat
override Cat.Name : string

Full name: Script.Cat.Name
static member IoC.Register : mode:Mode * factory:(unit -> 'T) * ?param:string -> unit
static member IoC.RegisterValue : value:'T * ?param:string -> unit
val cat : Cat

Full name: Script.cat
static member IoC.Resolve : ?param:string -> 'T
val me : IAnimal

Full name: Script.me
member Cat.Purr : unit -> unit
property IAnimal.Name: string
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>

More information

Link:http://fssnip.net/dg
Posted:4 years ago
Author:Eirik Tsarpalis
Tags: dependency injection , ioc