...
Mixin
...
scopes
...
are
...
useful
...
for
...
mixing
...
at
...
run-time
...
and
...
limiting
...
the
...
"reach
...
of
...
action"
...
for
...
certain
...
mixins.
...
If
...
nothing
...
else,
...
this
...
is
...
eminently
...
useful
...
for
...
testing.
...
This
...
page
...
explains
...
how
...
to
...
construct
...
and
...
use
...
mixin
...
scopes.
...
The
...
...
...
...
's
...
Hotel.Tests
...
project
...
makes
...
good
...
use
...
of
...
transaction
...
scopes
...
for
...
testing.
...
In
...
the
...
previous
...
example,
...
we
...
have
...
made
...
an
...
entirely
...
home-grown
...
configuration
...
the
...
active
...
configuration
...
for
...
the
...
entire
...
thread.
...
For
...
the
...
following
...
example,
...
we
...
will
...
introduce
...
three
...
modifications
...
to
...
that
...
idea.
...
- We
...
- will
...
- derive
...
- our
...
- custom
...
- configuration
...
- from
...
- the
...
- existing
...
- default
...
- master
...
- configuration
...
- (which
...
- in
...
- turn
...
- is
...
- a
...
- reflection
...
- of
...
- all
...
- the
...
Extends
...
- and
...
Uses
...
- attributes
...
- in
...
- the
...
- application).
...
- Instead
...
- of
...
- adding
...
- to
...
- that
...
- configuration,
...
- we
...
- will
...
- remove
...
- from
...
- it
...
- with
...
SuppressMixin<>
...
- .
...
- We
...
- will
...
- make
...
- the
...
- custom
...
- configuration
...
- active
...
- within
...
- a
...
- limited
...
- scope
...
- ,
...
- i.e.
...
- temporarily.
...
Since
...
the
...
simplistic
...
dessert
...
wax
...
sample
...
does
...
not
...
lend
...
itself
...
very
...
well
...
to
...
our
...
sophisticated
...
endeavor,
...
we
...
will
...
resort
...
to
...
the
...
slightly
...
more
...
advanced
...
parrot
...
on
...
a
...
unicycle
...
here.
...
The
...
following
...
sample
...
is
...
based
...
on
...
the
...
class
...
hierarchy
...
of
...
parrots
...
from
...
the
...
page
...
...
...
...
...
...
...
...
...
...
...
...
[ Parrot
, GreyParrot
and Macaw
, with Parrot
being the base class for GreyParrot
and Macaw
. ]
The entire hierarchy is extended by the CircusMixin
which gives the entire hierarchy the ability to ride a unicycle. This configuration is read in and made the master configuration, which in turn is the active configuration for the given task.
Since we can't modify an existing configuration, we have to build a new one based upon the active configuration and make the active configuration for our thread.
As explained on page re-motion mixins basics -- what about sub-classes of the target class? the entire class hierarchy is extended by a mixin if that mixin is applied to the base class. In our example, we will exempt the Macaw
class from being mixed. The new methods in the following snippet are
MixinConfiguration.BuildFromActive ()
– clones the active configurationSupressMixin<> ()
– removes the specified mixin from the given class
Code Block |
---|
var t = typeof (IMixinTarget);
var myMixinConfiguration = MixinConfiguration.BuildFromActive () // build upon active configuration
.ForClass<Macaw> ().SuppressMixin<CircusMixin> () // remove the circus mixin from the 'Macaw' class
.BuildConfiguration (); // finish construction
{code}
|
At
...
this
...
point
...
we
...
have
...
a
...
new
...
mixin
...
configuration
...
in
...
the
...
myMixinConfiguration
...
variable.
...
It
...
is
...
exactly
...
like
...
the
...
default
...
master
...
configuration
...
that
...
has
...
been
...
assembled
...
from
...
inspection
...
of
...
the
...
executable.
...
In
...
the
...
default
...
master
...
configuration,
...
the
...
CircusMixin
...
is
...
applied
...
to
...
Parrot
...
,
...
GreyParrot
...
and
...
Macaw
...
.
...
In
...
our
...
improved
...
clone,
...
the
...
CircusMixin
...
is
...
only
...
applied
...
to
...
Parrot
...
and
...
GreyParrot
...
.
...
Note
...
that
...
we
...
haven't
...
made
...
the
...
configuration
...
active
...
yet.
...
Remember
...
that
...
we
...
want
...
to
...
do
...
it
...
temporarily,
...
not
...
for
...
the
...
entire
...
life-time
...
of
...
the
...
thread.
...
For
...
this,
...
we
...
have
...
to
...
create
...
a
...
mixin
...
configuration
...
scope
...
from
...
myMixinConfiguration
...
.
...
You
...
do
...
this
...
with
...
the
...
method
...
EnterScope
...
:
...
Code Block |
---|
... some configuration is active here ...
using (myMixinConfiguration.EnterScope ())
{
... code code code ...
... where 'myMixinConfiguration' is active ...
} // end of scope
... previous mixin configuration is active again ...
{code}
The {{using}} spans the _scope_ for which the configuration is active. As soon as execution of the code passes the closing bracket {{\}}} of the {{using}}, the cloned configuration vanishes and the previous configuration becomes active again. (People who know the PhoneBook tutorial will recognize this mechanism: this is how [re-store]s _transaction scopes_ work.)
You can even nest such scopes to arbitrary depth:
{code} |
The using
spans the scope for which the configuration is active. As soon as execution of the code passes the closing bracket }
of the using
, the cloned configuration vanishes and the previous configuration becomes active again. (People who know the PhoneBook tutorial will recognize this mechanism: this is how re-stores transaction scopes work.)
You can even nest such scopes to arbitrary depth:
Code Block |
---|
... configuration A is active here ...
using (mixinConfiguration_B.EnterScope ())
{
... code code code ...
... where 'mixinConfiguration_B' is active ...
using (mixinConfiguration_C.EnterScope ())
{
... code code code ...
where 'mixinConfiguration_C' is active ...
} // end of scope for mixinConfiguration_C
... mixinConfiguration_C is active again ...
} // end of scope for mixinConfiguration_B
{code}
The following code sample utilizes {{using}} for our special configuration that has mixing for {{Macaw}} suppressed.
{code} |
The following code sample utilizes using
for our special configuration that has mixing for Macaw
suppressed.
Code Block |
---|
class Program
{
static void Main (string[] args)
{
// mind the loading of 'Remotion.dll'!
var t = typeof (IMixinTarget);
var myMixinConfiguration = MixinConfiguration.BuildFromActive () // clone the currently active configuration
// (that happens to be the master default config
// at this point)
.ForClass<Macaw> ().SuppressMixin<CircusMixin> () // remove the mixing of the circus mixin from the 'Macaw' class
.BuildConfiguration (); // cause the actual building of our clonee
// now we span a scope for our special configuration
using (myMixinConfiguration.EnterScope ())
{
// The mixed parrot class works as usual, no suppression here
var myCircusParrot = ObjectFactory.Create<Parrot> (ParamList.Empty);
Console.WriteLine ("Parrot:");
myCircusParrot.Whistle();
((ICircusMixin) myCircusParrot).RideUniCycle();
Console.WriteLine();
// The mixed grey parrot class works as usua, no suppression here either
Console.WriteLine ("GreyParrot:");
var myCircusGreyParrot = ObjectFactory.Create<GreyParrot> (ParamList.Empty);
myCircusGreyParrot.DestroyFurniture();
((ICircusMixin) myCircusGreyParrot).RideUniCycle();
Console.WriteLine();
// The macaw can do as macaws do (crack nuts)...
Console.WriteLine ("Macaw:");
var myBogusCircusMacaw = ObjectFactory.Create<Macaw> (ParamList.Empty);
myBogusCircusMacaw.CrackNut();
try
{
// ... but it can't ride the unicycle, because that's been
// suppressed
((ICircusMixin) myBogusCircusMacaw).RideUniCycle ();
}
catch (InvalidCastException)
{
// ... what gives us a bummer at run-time
Console.WriteLine ("... or not. We caught an 'InvalidCastException'.");
Console.WriteLine ("The 'Macaw' class can't be cast to 'ICircusMixin'");
Console.WriteLine ("because we suppressed that mixin. (Remember?)");
}
Console.WriteLine();
} // end of scope with the non-unicycle macaw
// at this point, the original (default master) configuration
// is active again, so the macaw CAN ride the unicycle
Console.WriteLine ("Macaw:");
var myWorkingCircusMacaw = ObjectFactory.Create<Macaw> (ParamList.Empty);
myWorkingCircusMacaw.CrackNut ();
((ICircusMixin) myWorkingCircusMacaw).RideUniCycle ();
Console.WriteLine ();
Console.ReadLine ();
}
}
{code}
|
If
...
you
...
need
...
the
...
new
...
configuration
...
only
...
once,
...
you
...
can
...
directly
...
call
...
EnterScope
...
on
...
the
...
builder
...
without
...
using
...
BuildConfiguration
...
.
...
BuildConfiguration
...
is
...
useful
...
when
...
you
...
need
...
to
...
store
...
the
...
configuration
...
in
...
a
...
variable
...
in
...
order
...
to
...
use
...
it
...
more
...
than
...
once.
...
Sample code
You find the complete sample code for this exercise in subversion
A more elaborate, and common, application of mixin scopes can be found in the unit-tests of the Hotel mixin sample, discussed there.