LiveUI Contracts.
LiveUI provides Contracts for dependencies management. If some interface is declared
as a Contract for Component then interface this implementation will be automatically
resolved for Component. I.e Components work as dependency injection containers for
Contracts. This document describes how to declare and how to use Contracts.
Declaring Contracts
Technically, Contract is a marker interface describing Component-Contract relationship.
There is Contract declaration example
Contract declaration sample
- public
interface
IView :
IContract<VisualComponent,
IView>
- {
- }
As one can see IContract interface has two generic arguments, first one is Component
Contract designed for and second is type itself. Second generic argument looks redundant
because it just repeats type implementing interface but for technical reasons it
can not be omitted.
The same syntax is used for Contract implementation.
Contract implementation Sample
- public
class
MyView :
IView,
IContract<MyComponent,
View>
- {
- }
Which means that View should be used as IView for MyComponentUsing Contracts
LiveUI provides following syntax for accessing Contracts:
Contract using sample
- var myComponent =
new MyComponent();
- IView view = visualComponent.GetContracts().Get<IView>();
That's what happens at line 2
- IView interface will be resolved as View
- new View instance would be created and accosiated with myComponent.
- View instance would be cached in Component
There are important features of Contracts:
- If one accesses the same contract for the same component then the same instance
will be returned;
Accessing contracts sample#1
- var visualComponent =
new MyComponent();
- IView view1 = visualComponent.GetContracts().Get<IView>();
- IView view2 = visualComponent.GetContracts().Get<IView>();
- Assert.AreEqual(view1, view2);
- If one contract inherits other contract the same same instance will be returned;
Declaring inherited contracts
- public
class
CustomView :
View, IContract<MyComponent,
CustomView>
- {
- }
Accessing contracts sample#2
- View view = visualComponent.GetContracts().Get<View>();
- CustomView customView = visualComponent.GetContracts().Get<CustomView>();
- Assert.AreEqual(customView,
view);
Typically contracts are used for:
- Making components loosely coupled.
At samples above
MyComponent knows nothing about View; it knows about IView only. Thus Component
and IView are loosely coupled which helps testing.
- Associating some information with component.
Sometimes
it is needed to associate some information with component without component
knowing about it. For example, when application starts some environment options
can be associated with root component.
Note: To make component accessible from contract, contract type should have
constructor with single argument of component type.
Registering Contracts
To make contracts work, assembly should be registered as a module using LiveUI
configuration section. For example, if we implement contracts at assembly named
MyFirstApplication, following should be added to configuration.
- <LiveUI>
- <Modules>
-
<add
moduleName="myApplication"
moduleAssembly="MyFirstApplication"
/>
- </Modules>
- </LiveUI>
How It Works ?
When application starts, built in ContractsModule is activated.
ContractsModules iterates through all registered types and searches for
IContract interface implementations. Having all IContracts it creates plan of
how each contract should be instantiated.
Internally Component uses sort of Dictionary to keep resolved contracts. When
Contract is accessed, Component looks at dictionary and returns instance if it
exists, else it uses ContractsModule to create new instance.
|