13 people like it.

Mini IoC Container

Minimal Inversion of Control (IoC) Container for Dependency Injection (DI) in under 100 lines of code. Implements the 3 Rs of DI: Register, Resolve, Release. Note: missing thread safety and fluent interface.

  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: 
 77: 
 78: 
 79: 
 80: 
 81: 
 82: 
 83: 
 84: 
 85: 
 86: 
 87: 
 88: 
 89: 
 90: 
 91: 
 92: 
 93: 
 94: 
 95: 
 96: 
 97: 
 98: 
 99: 
100: 
101: 
102: 
103: 
104: 
105: 
106: 
107: 
108: 
109: 
110: 
111: 
112: 
113: 
114: 
115: 
116: 
117: 
118: 
119: 
120: 
121: 
122: 
123: 
124: 
125: 
126: 
127: 
128: 
129: 
130: 
131: 
132: 
133: 
134: 
135: 
136: 
137: 
138: 
139: 
140: 
141: 
142: 
143: 
144: 
145: 
146: 
147: 
148: 
149: 
150: 
151: 
152: 
153: 
154: 
155: 
156: 
157: 
158: 
159: 
160: 
161: 
162: 
163: 
164: 
165: 
166: 
167: 
168: 
169: 
170: 
171: 
172: 
173: 
174: 
175: 
176: 
177: 
178: 
179: 
180: 
181: 
182: 
183: 
184: 
185: 
186: 
187: 
188: 
189: 
190: 
191: 
192: 
193: 
194: 
195: 
196: 
197: 
198: 
199: 
200: 
201: 
202: 
203: 
204: 
205: 
206: 
207: 
208: 
209: 
210: 
211: 
212: 
213: 
214: 
215: 
216: 
217: 
218: 
219: 
220: 
221: 
222: 
223: 
224: 
225: 
226: 
227: 
228: 
229: 
230: 
231: 
232: 
233: 
234: 
235: 
236: 
237: 
238: 
239: 
240: 
241: 
242: 
243: 
244: 
245: 
246: 
247: 
248: 
249: 
250: 
251: 
252: 
253: 
254: 
255: 
256: 
257: 
258: 
259: 
260: 
261: 
open System
open System.Collections.Generic
open System.Reflection
open Microsoft.FSharp.Reflection

type Message = string
exception TypeResolutionException of Message * Type
type Lifetime = Singleton | Transient
type AbstractType = Type
type ConcreteType = Type
type private Constructor = Reflected of ConcreteType | Factory of (unit -> obj)
let private (|FunType|_|) t =
    if FSharpType.IsFunction t then FSharpType.GetFunctionElements t |> Some
    else None
let private asOption = function Choice1Of2 x -> Some x | Choice2Of2 _ -> None
/// IoC Container
type Container () as container =
    let catalog = Dictionary<AbstractType, Constructor * Lifetime>()
    let singletons = Dictionary<ConcreteType,obj>()
    let rec tryResolve cs t =
        match catalog.TryGetValue t with
        | true, (Reflected u , lifetime) -> 
            tryObtain u (fun () -> tryReflect cs u) lifetime
        | true, (Factory f, lifetime) -> 
            tryObtain t (fun () -> f() |> Choice1Of2) lifetime
        | false, _ ->  
            tryObtain t (fun () -> tryReflect cs t) Singleton 
    and tryObtain t f lifetime =
        match singletons.TryGetValue t with
        | true, value -> Choice1Of2(value)
        | false, _ ->
            let result = f()
            result |> function Choice1Of2 value -> store t value lifetime | Choice2Of2 _ -> ()
            result
    and store t value = function Singleton -> singletons.Add(t,value) | Transient -> ()
    and tryReflect cs t =
        if cs |> List.exists ((=) t) then Choice2Of2 "Cycle detected" else tryConstructors (t::cs) t
    and tryConstructors cs t =
        let constructors =
            t.GetConstructors()
            |> Array.sortBy (fun c -> c.GetParameters().Length)
            |> Seq.map (tryConstructor cs)
        match constructors |> Seq.tryPick asOption with
        | Some value -> Choice1Of2 value
        | None -> constructorsError t constructors |> Choice2Of2
    and constructorsError t constructors =
        let constructors = constructors |> Seq.map (function Choice1Of2 _ -> "" | Choice2Of2 x -> x)
        "Failed to match constructor from:\r\n" + (constructors |> String.concat "\r\n")
    and tryConstructor cs ci =
        let ps = ci.GetParameters()
        let args = ps |> Array.map (fun p -> tryResolveArgument cs p.ParameterType)
        let args' = args |> Array.choose asOption
        if args'.Length = ps.Length then args' |> ci.Invoke |> Choice1Of2
        else constructorError ci.DeclaringType ps args |> Choice2Of2
    and constructorError t ps args =
        let ps = ps |> Seq.map (fun p -> p.Name + ":" + p.ParameterType.Name)
        let invalidArgs = args |> Seq.choose (function Choice2Of2 s -> Some s | Choice1Of2 _ -> None)
        t.Name + "(" + (String.concat "," ps) + ") -> " + (String.concat "\r\n" invalidArgs)
    and tryResolveArgument cs t =
        match t with
        | FunType(arg,result) when arg = typeof<unit> ->
            FSharpValue.MakeFunction(t,fun args -> container.Resolve(result)) |> Choice1Of2
        | t when t.IsPrimitive -> Choice2Of2 "Primitive arguments not supported"
        | t when t = typeof<string> -> Choice2Of2 "String arguments not supported"
        | t -> tryResolve cs t
    /// Register sequence of abstract types against specified concrete type
    member container.Register(abstractTypes:AbstractType seq, concreteType:ConcreteType) =
        for t in abstractTypes do catalog.Add(t, (Reflected concreteType, Singleton))
    /// Register abstract type against specified type instance
    member container.Register<'TAbstract>(instance:'TAbstract) =
        catalog.Add(typeof<'TAbstract>, (Reflected typeof<'TAbstract>, Singleton))
        singletons.Add(typeof<'TAbstract>, instance)
    /// Register abstract type against specified concrete type with given lifetime
    member container.Register<'TAbstract when 'TAbstract : not struct>
            (concreteType:ConcreteType, lifetime:Lifetime) =
        let abstractType = typeof<'TAbstract>
        if concreteType <> abstractType &&
           not (concreteType.IsSubclassOf(abstractType)) &&
           not (concreteType.GetInterfaces() |> Array.exists ((=) abstractType)) then
            invalidArg "concreteType" "Concrete type must implement abstract type"
        catalog.Add(abstractType, (Reflected concreteType, lifetime))
    /// Register abstract type against specified factory with given lifetime
    member container.Register<'TAbstract when 'TAbstract : not struct>
            (f:unit->'TAbstract, lifetime:Lifetime) = 
        catalog.Add(typeof<'TAbstract>, (Factory(f >> box), lifetime))
    /// Resolve instance of specified abstract type
    member container.Resolve<'TAbstract when 'TAbstract : not struct>() =
        container.Resolve(typeof<'TAbstract>) :?> 'TAbstract
    /// Resolve instsance of specified abstract type
    member container.Resolve(abstractType:AbstractType) =
        match tryResolve [] abstractType with
        | Choice1Of2 value -> value
        | Choice2Of2 message -> TypeResolutionException(message,abstractType) |> raise
    /// Remove instance reference from container
    member container.Release(instance:obj) =
        singletons |> Seq.filter (fun pair -> pair.Value = instance) |> Seq.toList
        |> List.iter (fun pair -> singletons.Remove(pair.Key) |> ignore)

open NUnit.Framework

[<TestFixture>]
module ``Container Register, Resolve, Release Tests`` =
    
    [<AbstractClass>]
    type AbstractType () = do ()

    type ConcreteType () = inherit AbstractType()

    type IMarkerInterface = interface end

    type MarkedType () = interface IMarkerInterface
    
    let [<Test>] ``registering 2 instances of an abstract type in a single container should throw`` () =
        let container = Container()
        container.Register<AbstractType>(typeof<AbstractType>, Singleton)
        Assert.Throws<System.ArgumentException>(fun () ->
            container.Register<AbstractType>(typeof<AbstractType>, Singleton) |> ignore
        ) |> ignore

    let [<Test>] ``registering a concrete type that does not implement the abstract type should throw`` () =
        let container = Container()
        Assert.Throws<System.ArgumentException>(fun () ->
            container.Register<MarkedType>(typeof<AbstractType>, Singleton)
        ) |> ignore

    let [<Test>] ``attempting to resolve an unregistered type should throw`` () =
        let container = Container()
        Assert.Throws<TypeResolutionException>(fun () ->  
            container.Resolve<AbstractType>() |> ignore
        ) |> ignore

    let [<Test>] ``resolving a registered abstract type should return an instance of the specified concrete type`` () =
        let container = Container()
        container.Register<AbstractType>(typeof<ConcreteType>, Singleton)
        let instance = container.Resolve<AbstractType>()
        Assert.True(instance :? ConcreteType)

    let [<Test>] ``resolving a type with a singleton lifetime should always return the same instance`` () =
        let container = Container()
        container.Register<AbstractType>(typeof<ConcreteType>, Singleton)
        let a = container.Resolve<AbstractType>()
        let b = container.Resolve<AbstractType>()
        Assert.True( Object.ReferenceEquals(a,b) )
        
    let [<Test>] ``resolving a type with a transient lifetime should a new instance each time`` () =
        let container = Container()
        container.Register<AbstractType>(typeof<ConcreteType>, Transient)
        let a = container.Resolve<AbstractType>()
        let b = container.Resolve<AbstractType>()
        Assert.AreNotSame(a,b)

    let [<Test>] ``resolving a registered instance of a type should return that instance`` () =
        let container = Container()
        let this = ConcreteType()
        container.Register<AbstractType>(this)
        let that = container.Resolve<AbstractType>()
        Assert.AreSame(this, that)

    let [<Test>] ``resolving a type registered as a factory should call the specified factory`` () =
        let called = ref false
        let factory = fun () -> called := true; ConcreteType() :> AbstractType
        let container = Container()
        container.Register<AbstractType>(factory, Singleton)
        container.Resolve<AbstractType>() |> ignore
        Assert.True( called.Value )

    let [<Test>] ``releasing a registered concrete instance then resolving the type should return a new concrete instance`` () =
        let container = Container()
        let this = ConcreteType()
        container.Register<ConcreteType>(this)
        container.Release(this)
        let that = container.Resolve<ConcreteType>()
        Assert.True( not <| Object.ReferenceEquals(this, that) )

    do
        ``registering 2 instances of an abstract type in a single container should throw`` ()
        ``attempting to resolve an unregistered type should throw`` ()
        ``resolving a registered abstract type should return an instance of the specified concrete type``  ()
        ``resolving a type with a singleton lifetime should always return the same instance`` ()
        ``resolving a type with a transient lifetime should a new instance each time`` ()
        ``resolving a registered instance of a type should return that instance`` ()
        ``resolving a type registered as a factory should call the specified factory`` ()
        ``releasing a registered concrete instance then resolving the type should return a new concrete instance`` ()

[<TestFixture>]
module ``Constructor Tests`` =
    
    [<AbstractClass>]
    type AbstractType () = do ()
   
    type ConstructorWithValueTypeArg (arg:int) = inherit AbstractType()

    let [<Test>] ``resolving type with value type dependency in constructor should throw`` () =
        let container = Container()
        container.Register<AbstractType>(typeof<ConstructorWithValueTypeArg>, Singleton)
        Assert.Throws<TypeResolutionException>(fun () ->
            container.Resolve<AbstractType>() |> ignore
        ) |> ignore

    type ReferenceType() = do ()
    type ConstructorWithReferenceTypeArg (arg:ReferenceType) = inherit AbstractType()

    let [<Test>] ``resolving type with reference type dependency in constructor should inject reference`` () =
        let container = Container()
        container.Register<AbstractType>(typeof<ConstructorWithReferenceTypeArg>, Singleton)
        let instance = container.Resolve<AbstractType>()
        Assert.NotNull(instance)

    type ConstructorWithSelfReferenceArg (arg:AbstractType) = inherit AbstractType()

    let [<Test>] ``resolving type with self type dependency in constructor should fail`` () =
        let container = Container()
        container.Register<AbstractType>(typeof<ConstructorWithSelfReferenceArg>, Singleton)
        Assert.Throws<TypeResolutionException>(fun () ->
                container.Resolve<AbstractType>() |> ignore
        ) |> ignore

    type Cyclic(arg:ConstructorWithCyclicReferenceArg) = do ()
    and  ConstructorWithCyclicReferenceArg (arg:Cyclic) = do ()

    let [<Test>] ``resolving type with cyclic type dependency in constructor should fail`` () =
        let container = Container()
        container.Register<ConstructorWithCyclicReferenceArg>(typeof<ConstructorWithCyclicReferenceArg>, Singleton)
        Assert.Throws<TypeResolutionException>(fun () ->
                container.Resolve<AbstractType>() |> ignore
        ) |> ignore

    type ConstructorWithFunArg (arg:unit -> ReferenceType) = 
        inherit AbstractType()
        member this.Factory () = arg()

    let [<Test>] ``resolving type with fun type argument in constructor should inject factory`` () =
        let container = Container()
        container.Register<AbstractType>(typeof<ConstructorWithFunArg>, Singleton)
        let instance = container.Resolve<AbstractType>() :?> ConstructorWithFunArg
        let refValue = instance.Factory()
        Assert.NotNull(refValue)

    do  ``resolving type with value type dependency in constructor should throw`` ()
        ``resolving type with reference type dependency in constructor should inject reference`` ()
        ``resolving type with self type dependency in constructor should fail`` ()
        ``resolving type with cyclic type dependency in constructor should fail`` ()
        ``resolving type with fun type argument in constructor should inject factory`` ()

module Usage =

    type ICalculate =
        abstract member Incr : int -> int

    type Calculator () =
        interface ICalculate with
            member this.Incr(x:int) = x + 1
    
    let container = Container()

    container.Register<ICalculate>(typeof<Calculator>, Singleton)

    let calc = container.Resolve<ICalculate>()
    printfn "%d" (calc.Incr 1)

    container.Release(calc)
namespace System
namespace System.Collections
namespace System.Collections.Generic
namespace System.Reflection
namespace Microsoft
namespace Microsoft.FSharp
namespace Microsoft.FSharp.Reflection
type Message = string

Full name: Script.Message
Multiple items
val string : value:'T -> string

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

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
exception TypeResolutionException of Message * Type

Full name: Script.TypeResolutionException
type Type =
  inherit MemberInfo
  member Assembly : Assembly
  member AssemblyQualifiedName : string
  member Attributes : TypeAttributes
  member BaseType : Type
  member ContainsGenericParameters : bool
  member DeclaringMethod : MethodBase
  member DeclaringType : Type
  member Equals : o:obj -> bool + 1 overload
  member FindInterfaces : filter:TypeFilter * filterCriteria:obj -> Type[]
  member FindMembers : memberType:MemberTypes * bindingAttr:BindingFlags * filter:MemberFilter * filterCriteria:obj -> MemberInfo[]
  ...

Full name: System.Type
type Lifetime =
  | Singleton
  | Transient

Full name: Script.Lifetime
union case Lifetime.Singleton: Lifetime
union case Lifetime.Transient: Lifetime
type AbstractType = Type

Full name: Script.AbstractType
type ConcreteType = Type

Full name: Script.ConcreteType
type private Constructor =
  | Reflected of ConcreteType
  | Factory of (unit -> obj)

Full name: Script.Constructor
union case Constructor.Reflected: ConcreteType -> Constructor
union case Constructor.Factory: (unit -> obj) -> Constructor
type unit = Unit

Full name: Microsoft.FSharp.Core.unit
type obj = Object

Full name: Microsoft.FSharp.Core.obj
val t : Type
type FSharpType =
  static member GetExceptionFields : exceptionType:Type * ?bindingFlags:BindingFlags -> PropertyInfo []
  static member GetFunctionElements : functionType:Type -> Type * Type
  static member GetRecordFields : recordType:Type * ?bindingFlags:BindingFlags -> PropertyInfo []
  static member GetTupleElements : tupleType:Type -> Type []
  static member GetUnionCases : unionType:Type * ?bindingFlags:BindingFlags -> UnionCaseInfo []
  static member IsExceptionRepresentation : exceptionType:Type * ?bindingFlags:BindingFlags -> bool
  static member IsFunction : typ:Type -> bool
  static member IsModule : typ:Type -> bool
  static member IsRecord : typ:Type * ?bindingFlags:BindingFlags -> bool
  static member IsTuple : typ:Type -> bool
  ...

Full name: Microsoft.FSharp.Reflection.FSharpType
static member FSharpType.IsFunction : typ:Type -> bool
static member FSharpType.GetFunctionElements : functionType:Type -> Type * Type
union case Option.Some: Value: 'T -> Option<'T>
union case Option.None: Option<'T>
val private asOption : _arg1:Choice<'a,'b> -> 'a option

Full name: Script.asOption
union case Choice.Choice1Of2: 'T1 -> Choice<'T1,'T2>
val x : 'a
union case Choice.Choice2Of2: 'T2 -> Choice<'T1,'T2>
Multiple items
type Container =
  new : unit -> Container
  member Register : instance:'TAbstract -> unit
  member Register : abstractTypes:seq<AbstractType> * concreteType:ConcreteType -> unit
  member Register : concreteType:ConcreteType * lifetime:Lifetime -> unit
  member Register : f:(unit -> 'TAbstract) * lifetime:Lifetime -> unit (requires reference type)
  member Release : instance:obj -> unit
  member Resolve : unit -> 'TAbstract (requires reference type)
  member Resolve : abstractType:AbstractType -> obj

Full name: Script.Container


 IoC Container


--------------------
new : unit -> Container
val container : Container
val catalog : Dictionary<AbstractType,(Constructor * Lifetime)>
Multiple items
type Dictionary<'TKey,'TValue> =
  new : unit -> Dictionary<'TKey, 'TValue> + 5 overloads
  member Add : key:'TKey * value:'TValue -> unit
  member Clear : unit -> unit
  member Comparer : IEqualityComparer<'TKey>
  member ContainsKey : key:'TKey -> bool
  member ContainsValue : value:'TValue -> bool
  member Count : int
  member GetEnumerator : unit -> Enumerator<'TKey, 'TValue>
  member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
  member Item : 'TKey -> 'TValue with get, set
  ...
  nested type Enumerator
  nested type KeyCollection
  nested type ValueCollection

Full name: System.Collections.Generic.Dictionary<_,_>

--------------------
Dictionary() : unit
Dictionary(capacity: int) : unit
Dictionary(comparer: IEqualityComparer<'TKey>) : unit
Dictionary(dictionary: IDictionary<'TKey,'TValue>) : unit
Dictionary(capacity: int, comparer: IEqualityComparer<'TKey>) : unit
Dictionary(dictionary: IDictionary<'TKey,'TValue>, comparer: IEqualityComparer<'TKey>) : unit
val singletons : Dictionary<ConcreteType,obj>
val tryResolve : (ConcreteType list -> AbstractType -> Choice<obj,string>)
val cs : ConcreteType list
val t : AbstractType
Dictionary.TryGetValue(key: AbstractType, value: byref<Constructor * Lifetime>) : bool
val u : ConcreteType
val lifetime : Lifetime
val tryObtain : (ConcreteType -> (unit -> Choice<obj,string>) -> Lifetime -> Choice<obj,string>)
val tryReflect : (ConcreteType list -> ConcreteType -> Choice<obj,string>)
val f : (unit -> obj)
val t : ConcreteType
val f : (unit -> Choice<obj,string>)
Dictionary.TryGetValue(key: ConcreteType, value: byref<obj>) : bool
val value : obj
val result : Choice<obj,string>
val store : (ConcreteType -> obj -> Lifetime -> unit)
Dictionary.Add(key: ConcreteType, value: obj) : unit
Multiple items
type List<'T> =
  new : unit -> List<'T> + 2 overloads
  member Add : item:'T -> unit
  member AddRange : collection:IEnumerable<'T> -> unit
  member AsReadOnly : unit -> ReadOnlyCollection<'T>
  member BinarySearch : item:'T -> int + 2 overloads
  member Capacity : int with get, set
  member Clear : unit -> unit
  member Contains : item:'T -> bool
  member ConvertAll<'TOutput> : converter:Converter<'T, 'TOutput> -> List<'TOutput>
  member CopyTo : array:'T[] -> unit + 2 overloads
  ...
  nested type Enumerator

Full name: System.Collections.Generic.List<_>

--------------------
List() : unit
List(capacity: int) : unit
List(collection: IEnumerable<'T>) : unit
val exists : predicate:('T -> bool) -> list:'T list -> bool

Full name: Microsoft.FSharp.Collections.List.exists
val tryConstructors : (ConcreteType list -> ConcreteType -> Choice<obj,string>)
val constructors : seq<Choice<obj,string>>
Type.GetConstructors() : ConstructorInfo []
Type.GetConstructors(bindingAttr: BindingFlags) : ConstructorInfo []
type Array =
  member Clone : unit -> obj
  member CopyTo : array:Array * index:int -> unit + 1 overload
  member GetEnumerator : unit -> IEnumerator
  member GetLength : dimension:int -> int
  member GetLongLength : dimension:int -> int64
  member GetLowerBound : dimension:int -> int
  member GetUpperBound : dimension:int -> int
  member GetValue : [<ParamArray>] indices:int[] -> obj + 7 overloads
  member Initialize : unit -> unit
  member IsFixedSize : bool
  ...

Full name: System.Array
val sortBy : projection:('T -> 'Key) -> array:'T [] -> 'T [] (requires comparison)

Full name: Microsoft.FSharp.Collections.Array.sortBy
val c : ConstructorInfo
MethodBase.GetParameters() : ParameterInfo []
module Seq

from Microsoft.FSharp.Collections
val map : mapping:('T -> 'U) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.map
val tryConstructor : (ConcreteType list -> ConstructorInfo -> Choice<obj,string>)
val tryPick : chooser:('T -> 'U option) -> source:seq<'T> -> 'U option

Full name: Microsoft.FSharp.Collections.Seq.tryPick
val constructorsError : (ConcreteType -> seq<Choice<obj,string>> -> string)
val constructors : seq<string>
val x : string
Multiple items
type String =
  new : value:char -> string + 7 overloads
  member Chars : int -> char
  member Clone : unit -> obj
  member CompareTo : value:obj -> int + 1 overload
  member Contains : value:string -> bool
  member CopyTo : sourceIndex:int * destination:char[] * destinationIndex:int * count:int -> unit
  member EndsWith : value:string -> bool + 2 overloads
  member Equals : obj:obj -> bool + 2 overloads
  member GetEnumerator : unit -> CharEnumerator
  member GetHashCode : unit -> int
  ...

Full name: System.String

--------------------
String(value: nativeptr<char>) : unit
String(value: nativeptr<sbyte>) : unit
String(value: char []) : unit
String(c: char, count: int) : unit
String(value: nativeptr<char>, startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int) : unit
String(value: char [], startIndex: int, length: int) : unit
String(value: nativeptr<sbyte>, startIndex: int, length: int, enc: Text.Encoding) : unit
val concat : sep:string -> strings:seq<string> -> string

Full name: Microsoft.FSharp.Core.String.concat
val ci : ConstructorInfo
val ps : ParameterInfo []
val args : Choice<obj,string> []
val map : mapping:('T -> 'U) -> array:'T [] -> 'U []

Full name: Microsoft.FSharp.Collections.Array.map
val p : ParameterInfo
val tryResolveArgument : (ConcreteType list -> Type -> Choice<obj,string>)
property ParameterInfo.ParameterType: Type
val args' : obj []
val choose : chooser:('T -> 'U option) -> array:'T [] -> 'U []

Full name: Microsoft.FSharp.Collections.Array.choose
property Array.Length: int
ConstructorInfo.Invoke(parameters: obj []) : obj
MethodBase.Invoke(obj: obj, parameters: obj []) : obj
ConstructorInfo.Invoke(invokeAttr: BindingFlags, binder: Binder, parameters: obj [], culture: Globalization.CultureInfo) : obj
MethodBase.Invoke(obj: obj, invokeAttr: BindingFlags, binder: Binder, parameters: obj [], culture: Globalization.CultureInfo) : obj
val constructorError : (Type -> ParameterInfo [] -> Choice<obj,string> [] -> string)
property MemberInfo.DeclaringType: Type
val ps : seq<string>
property ParameterInfo.Name: string
property MemberInfo.Name: string
val invalidArgs : seq<string>
val choose : chooser:('T -> 'U option) -> source:seq<'T> -> seq<'U>

Full name: Microsoft.FSharp.Collections.Seq.choose
val s : string
active recognizer FunType: Type -> (Type * Type) option

Full name: Script.( |FunType|_| )
val arg : Type
val result : Type
val typeof<'T> : Type

Full name: Microsoft.FSharp.Core.Operators.typeof
type FSharpValue =
  static member GetExceptionFields : exn:obj * ?bindingFlags:BindingFlags -> obj []
  static member GetRecordField : record:obj * info:PropertyInfo -> obj
  static member GetRecordFields : record:obj * ?bindingFlags:BindingFlags -> obj []
  static member GetTupleField : tuple:obj * index:int -> obj
  static member GetTupleFields : tuple:obj -> obj []
  static member GetUnionFields : value:obj * unionType:Type * ?bindingFlags:BindingFlags -> UnionCaseInfo * obj []
  static member MakeFunction : functionType:Type * implementation:(obj -> obj) -> obj
  static member MakeRecord : recordType:Type * values:obj [] * ?bindingFlags:BindingFlags -> obj
  static member MakeTuple : tupleElements:obj [] * tupleType:Type -> obj
  static member MakeUnion : unionCase:UnionCaseInfo * args:obj [] * ?bindingFlags:BindingFlags -> obj
  ...

Full name: Microsoft.FSharp.Reflection.FSharpValue
static member FSharpValue.MakeFunction : functionType:Type * implementation:(obj -> obj) -> obj
val args : obj
member Container.Resolve : unit -> 'TAbstract (requires reference type)


 Resolve instance of specified abstract type

member Container.Resolve : abstractType:AbstractType -> obj


 Resolve instsance of specified abstract type
property Type.IsPrimitive: bool
member Container.Register : abstractTypes:seq<AbstractType> * concreteType:ConcreteType -> unit

Full name: Script.Container.Register


 Register sequence of abstract types against specified concrete type
val abstractTypes : seq<AbstractType>
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

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

--------------------
type seq<'T> = IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
val concreteType : ConcreteType
Dictionary.Add(key: AbstractType, value: Constructor * Lifetime) : unit
member Container.Register : instance:'TAbstract -> unit

Full name: Script.Container.Register


 Register abstract type against specified type instance
val instance : 'TAbstract
member Container.Register : concreteType:ConcreteType * lifetime:Lifetime -> unit

Full name: Script.Container.Register


 Register abstract type against specified concrete type with given lifetime
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
val abstractType : Type
Type.IsSubclassOf(c: Type) : bool
Type.GetInterfaces() : Type []
val exists : predicate:('T -> bool) -> array:'T [] -> bool

Full name: Microsoft.FSharp.Collections.Array.exists
val invalidArg : argumentName:string -> message:string -> 'T

Full name: Microsoft.FSharp.Core.Operators.invalidArg
member Container.Register : f:(unit -> 'TAbstract) * lifetime:Lifetime -> unit (requires reference type)

Full name: Script.Container.Register


 Register abstract type against specified factory with given lifetime
val f : (unit -> 'TAbstract) (requires reference type)
val box : value:'T -> obj

Full name: Microsoft.FSharp.Core.Operators.box
member Container.Resolve : unit -> 'TAbstract (requires reference type)

Full name: Script.Container.Resolve


 Resolve instance of specified abstract type
member Container.Resolve : abstractType:AbstractType -> obj

Full name: Script.Container.Resolve


 Resolve instsance of specified abstract type
val abstractType : AbstractType
val message : string
val raise : exn:Exception -> 'T

Full name: Microsoft.FSharp.Core.Operators.raise
member Container.Release : instance:obj -> unit

Full name: Script.Container.Release


 Remove instance reference from container
val instance : obj
val filter : predicate:('T -> bool) -> source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.filter
val pair : KeyValuePair<ConcreteType,obj>
property KeyValuePair.Value: obj
val toList : source:seq<'T> -> 'T list

Full name: Microsoft.FSharp.Collections.Seq.toList
val iter : action:('T -> unit) -> list:'T list -> unit

Full name: Microsoft.FSharp.Collections.List.iter
Dictionary.Remove(key: ConcreteType) : bool
property KeyValuePair.Key: ConcreteType
val ignore : value:'T -> unit

Full name: Microsoft.FSharp.Core.Operators.ignore
namespace NUnit
namespace NUnit.Framework
Multiple items
type TestFixtureAttribute =
  inherit NUnitAttribute
  new : unit -> TestFixtureAttribute + 1 overload
  member Arguments : obj[] with get, set
  member Author : string with get, set
  member BuildFrom : typeInfo:ITypeInfo -> IEnumerable<TestSuite>
  member Category : string with get, set
  member Description : string with get, set
  member Explicit : bool with get, set
  member Ignore : string with get, set
  member IgnoreReason : string with get, set
  member Properties : IPropertyBag with get, set
  ...

Full name: NUnit.Framework.TestFixtureAttribute

--------------------
TestFixtureAttribute() : unit
TestFixtureAttribute([<ParamArray>] arguments: obj []) : unit
Multiple items
type AbstractClassAttribute =
  inherit Attribute
  new : unit -> AbstractClassAttribute

Full name: Microsoft.FSharp.Core.AbstractClassAttribute

--------------------
new : unit -> AbstractClassAttribute
Multiple items
type AbstractType =
  new : unit -> AbstractType

Full name: Script.Container Register, Resolve, Release Tests.AbstractType

--------------------
new : unit -> Container Register<...>.AbstractType
Multiple items
type ConcreteType =
  inherit AbstractType
  new : unit -> ConcreteType

Full name: Script.Container Register, Resolve, Release Tests.ConcreteType

--------------------
new : unit -> Container Register<...>.ConcreteType
type IMarkerInterface

Full name: Script.Container Register, Resolve, Release Tests.IMarkerInterface
Multiple items
type MarkedType =
  interface IMarkerInterface
  new : unit -> MarkedType

Full name: Script.Container Register, Resolve, Release Tests.MarkedType

--------------------
new : unit -> Container Register<...>.MarkedType
Multiple items
type TestAttribute =
  inherit NUnitAttribute
  new : unit -> TestAttribute
  member ApplyToTest : test:Test -> unit
  member Author : string with get, set
  member BuildFrom : method:IMethodInfo * suite:Test -> TestMethod
  member Description : string with get, set
  member ExpectedResult : obj with get, set
  member HasExpectedResult : bool with get, set
  member TestOf : Type with get, set

Full name: NUnit.Framework.TestAttribute

--------------------
TestAttribute() : unit
val ( registering 2 instances of an abstract type in a single container should throw ) : unit -> unit

Full name: Script.Container Register, Resolve, Release Tests.( registering 2 instances of an abstract type in a single container should throw )
member Container.Register : instance:'TAbstract -> unit


 Register abstract type against specified type instance

member Container.Register : abstractTypes:seq<AbstractType> * concreteType:ConcreteType -> unit


 Register sequence of abstract types against specified concrete type

member Container.Register : concreteType:ConcreteType * lifetime:Lifetime -> unit


 Register abstract type against specified concrete type with given lifetime

member Container.Register : f:(unit -> 'TAbstract) * lifetime:Lifetime -> unit (requires reference type)


 Register abstract type against specified factory with given lifetime
type Assert =
  static member AreEqual : expected:obj * actual:obj -> unit + 5 overloads
  static member AreNotEqual : expected:obj * actual:obj -> unit + 1 overload
  static member AreNotSame : expected:obj * actual:obj -> unit + 1 overload
  static member AreSame : expected:obj * actual:obj -> unit + 1 overload
  static member ByVal : actual:obj * expression:IResolveConstraint -> unit + 1 overload
  static member Catch : code:TestDelegate -> Exception + 5 overloads
  static member Contains : expected:obj * actual:ICollection -> unit + 1 overload
  static member DoesNotThrow : code:TestDelegate -> unit + 1 overload
  static member Equals : a:obj * b:obj -> bool
  static member Fail : unit -> unit + 2 overloads
  ...

Full name: NUnit.Framework.Assert
Assert.Throws<'TActual (requires 'TActual :> exn)>(code: TestDelegate) : 'TActual
Assert.Throws(expectedExceptionType: Type, code: TestDelegate) : exn
Assert.Throws(expression: Constraints.IResolveConstraint, code: TestDelegate) : exn
Assert.Throws<'TActual (requires 'TActual :> exn)>(code: TestDelegate, message: string, [<ParamArray>] args: obj []) : 'TActual
Assert.Throws(expectedExceptionType: Type, code: TestDelegate, message: string, [<ParamArray>] args: obj []) : exn
Assert.Throws(expression: Constraints.IResolveConstraint, code: TestDelegate, message: string, [<ParamArray>] args: obj []) : exn
Multiple items
type ArgumentException =
  inherit SystemException
  new : unit -> ArgumentException + 4 overloads
  member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
  member Message : string
  member ParamName : string

Full name: System.ArgumentException

--------------------
ArgumentException() : unit
ArgumentException(message: string) : unit
ArgumentException(message: string, innerException: exn) : unit
ArgumentException(message: string, paramName: string) : unit
ArgumentException(message: string, paramName: string, innerException: exn) : unit
val ( registering a concrete type that does not implement the abstract type should throw ) : unit -> unit

Full name: Script.Container Register, Resolve, Release Tests.( registering a concrete type that does not implement the abstract type should throw )
val ( attempting to resolve an unregistered type should throw ) : unit -> unit

Full name: Script.Container Register, Resolve, Release Tests.( attempting to resolve an unregistered type should throw )
val ( resolving a registered abstract type should return an instance of the specified concrete type ) : unit -> unit

Full name: Script.Container Register, Resolve, Release Tests.( resolving a registered abstract type should return an instance of the specified concrete type )
val instance : Container Register<...>.AbstractType
Assert.True(condition: bool) : unit
Assert.True(condition: Nullable<bool>) : unit
Assert.True(condition: bool, message: string, [<ParamArray>] args: obj []) : unit
Assert.True(condition: Nullable<bool>, message: string, [<ParamArray>] args: obj []) : unit
val ( resolving a type with a singleton lifetime should always return the same instance ) : unit -> unit

Full name: Script.Container Register, Resolve, Release Tests.( resolving a type with a singleton lifetime should always return the same instance )
val a : Container Register<...>.AbstractType
val b : Container Register<...>.AbstractType
Multiple items
type Object =
  new : unit -> obj
  member Equals : obj:obj -> bool
  member GetHashCode : unit -> int
  member GetType : unit -> Type
  member ToString : unit -> string
  static member Equals : objA:obj * objB:obj -> bool
  static member ReferenceEquals : objA:obj * objB:obj -> bool

Full name: System.Object

--------------------
Object() : unit
Object.ReferenceEquals(objA: obj, objB: obj) : bool
val ( resolving a type with a transient lifetime should a new instance each time ) : unit -> unit

Full name: Script.Container Register, Resolve, Release Tests.( resolving a type with a transient lifetime should a new instance each time )
Assert.AreNotSame(expected: obj, actual: obj) : unit
Assert.AreNotSame(expected: obj, actual: obj, message: string, [<ParamArray>] args: obj []) : unit
val ( resolving a registered instance of a type should return that instance ) : unit -> unit

Full name: Script.Container Register, Resolve, Release Tests.( resolving a registered instance of a type should return that instance )
val this : Container Register<...>.ConcreteType
val that : Container Register<...>.AbstractType
Assert.AreSame(expected: obj, actual: obj) : unit
Assert.AreSame(expected: obj, actual: obj, message: string, [<ParamArray>] args: obj []) : unit
val ( resolving a type registered as a factory should call the specified factory ) : unit -> unit

Full name: Script.Container Register, Resolve, Release Tests.( resolving a type registered as a factory should call the specified factory )
val called : bool ref
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 factory : (unit -> Container Register<...>.AbstractType)
property Ref.Value: bool
val ( releasing a registered concrete instance then resolving the type should return a new concrete instance ) : unit -> unit

Full name: Script.Container Register, Resolve, Release Tests.( releasing a registered concrete instance then resolving the type should return a new concrete instance )
member Container.Release : instance:obj -> unit


 Remove instance reference from container
val that : Container Register<...>.ConcreteType
Multiple items
type AbstractType =
  new : unit -> AbstractType

Full name: Script.Constructor Tests.AbstractType

--------------------
new : unit -> AbstractType
Multiple items
type ConstructorWithValueTypeArg =
  inherit AbstractType
  new : arg:int -> ConstructorWithValueTypeArg

Full name: Script.Constructor Tests.ConstructorWithValueTypeArg

--------------------
new : arg:int -> ConstructorWithValueTypeArg
val arg : int
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<_>
val ( resolving type with value type dependency in constructor should throw ) : unit -> unit

Full name: Script.Constructor Tests.( resolving type with value type dependency in constructor should throw )
Multiple items
type ReferenceType =
  new : unit -> ReferenceType

Full name: Script.Constructor Tests.ReferenceType

--------------------
new : unit -> ReferenceType
Multiple items
type ConstructorWithReferenceTypeArg =
  inherit AbstractType
  new : arg:ReferenceType -> ConstructorWithReferenceTypeArg

Full name: Script.Constructor Tests.ConstructorWithReferenceTypeArg

--------------------
new : arg:ReferenceType -> ConstructorWithReferenceTypeArg
val arg : ReferenceType
val ( resolving type with reference type dependency in constructor should inject reference ) : unit -> unit

Full name: Script.Constructor Tests.( resolving type with reference type dependency in constructor should inject reference )
val instance : AbstractType
Assert.NotNull(anObject: obj) : unit
Assert.NotNull(anObject: obj, message: string, [<ParamArray>] args: obj []) : unit
Multiple items
type ConstructorWithSelfReferenceArg =
  inherit AbstractType
  new : arg:AbstractType -> ConstructorWithSelfReferenceArg

Full name: Script.Constructor Tests.ConstructorWithSelfReferenceArg

--------------------
new : arg:AbstractType -> ConstructorWithSelfReferenceArg
val arg : AbstractType
val ( resolving type with self type dependency in constructor should fail ) : unit -> unit

Full name: Script.Constructor Tests.( resolving type with self type dependency in constructor should fail )
Multiple items
type Cyclic =
  new : arg:ConstructorWithCyclicReferenceArg -> Cyclic

Full name: Script.Constructor Tests.Cyclic

--------------------
new : arg:ConstructorWithCyclicReferenceArg -> Cyclic
val arg : ConstructorWithCyclicReferenceArg
Multiple items
type ConstructorWithCyclicReferenceArg =
  new : arg:Cyclic -> ConstructorWithCyclicReferenceArg

Full name: Script.Constructor Tests.ConstructorWithCyclicReferenceArg

--------------------
new : arg:Cyclic -> ConstructorWithCyclicReferenceArg
val arg : Cyclic
val ( resolving type with cyclic type dependency in constructor should fail ) : unit -> unit

Full name: Script.Constructor Tests.( resolving type with cyclic type dependency in constructor should fail )
Multiple items
type ConstructorWithFunArg =
  inherit AbstractType
  new : arg:(unit -> ReferenceType) -> ConstructorWithFunArg
  member Factory : unit -> ReferenceType

Full name: Script.Constructor Tests.ConstructorWithFunArg

--------------------
new : arg:(unit -> ReferenceType) -> ConstructorWithFunArg
val arg : (unit -> ReferenceType)
val this : ConstructorWithFunArg
member ConstructorWithFunArg.Factory : unit -> ReferenceType

Full name: Script.Constructor Tests.ConstructorWithFunArg.Factory
val ( resolving type with fun type argument in constructor should inject factory ) : unit -> unit

Full name: Script.Constructor Tests.( resolving type with fun type argument in constructor should inject factory )
val instance : ConstructorWithFunArg
val refValue : ReferenceType
member ConstructorWithFunArg.Factory : unit -> ReferenceType
module Usage

from Script
type ICalculate =
  interface
    abstract member Incr : int -> int
  end

Full name: Script.Usage.ICalculate
abstract member ICalculate.Incr : int -> int

Full name: Script.Usage.ICalculate.Incr
Multiple items
type Calculator =
  interface ICalculate
  new : unit -> Calculator

Full name: Script.Usage.Calculator

--------------------
new : unit -> Calculator
val this : Calculator
override Calculator.Incr : x:int -> int

Full name: Script.Usage.Calculator.Incr
val x : int
val container : Container

Full name: Script.Usage.container
val calc : ICalculate

Full name: Script.Usage.calc
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
abstract member ICalculate.Incr : int -> int

More information

Link:http://fssnip.net/9g
Posted:5 years ago
Author:Phillip Trelford
Tags: di , ioc , dependency injection , container