...
New
...
Shimmer
...
– a
...
dessert
...
topping
...
AND
...
a
...
floor
...
wax!
...
A
...
classic
...
example
...
for
...
multiple
...
inheritance
...
is
...
based
...
on
...
a
...
Saturday
...
Night
...
Live
...
parody
...
ad
...
starring
...
Chevy
...
Chase:
...
...
...
.
...
Is
...
New
...
Shimmer
...
a
...
dessert
...
topping?
...
Is
...
it
...
a
...
floor
...
wax?
...
The
...
answer
...
is:
...
both!
...
So
...
we
...
have
...
two
...
classes
...
-
...
DessertTopping
...
and
...
FloorWax
...
-
...
and
...
desire
...
to
...
inherit
...
from
...
both
...
of
...
them,
...
giving
...
us
...
a
...
dessert
...
wax
...
:
...
Code Block |
---|
public class DessertTopping
{
public void TasteGood ()
{
Console.WriteLine ("Mmmmmm, tastes terrific!");
}
}
public class FloorWax
{
public void SealFloor ()
{
Console.WriteLine ("Dirt, grime, even black heel marks -- wipe clean with a damp mop!");
}
}
{code}
|
The
...
result
...
of
...
our
...
mixing
...
will
...
be
...
a
...
new
...
class
...
that
...
is
...
generated
...
by
...
re-motion's
...
factory,
...
which
...
also
...
instantiates
...
that
...
class:
...
Code Block |
---|
// generate the class that "inherits" dessert topping members and floor wax members
// and instantiate that class
var myDessertWax = ObjectFactory.Create<DessertTopping> (ParamList.Empty);
{code}
The {{myDessertWax}} instance will be able to execute both the
- {{TasteGood}}
- {{SealFloor}}
methods.
For this to work, you
- refashion the {{FloorWax}} class as a mixin class
- MUST use the {{ObjectFactory}} to instantiate your mixed class ({{DessertWax}} -- instantiating with {{new}} won't do much in terms of mixing here.
- create a _mixin configuration_ with attributes, for the {{ObjectFactory}} to process
It is the {{ObjectFactory}} that learns how you have set up your code and how target classes are extended by mixins classes. The type-paramter {{DessertTopping}} in
{code} |
The myDessertWax
instance will be able to execute both the
TasteGood
SealFloor
methods.
For this to work, you
- refashion the
FloorWax
class as a mixin class - MUST use the
ObjectFactory
to instantiate your mixed class (DessertWax
– instantiating withnew
won't do much in terms of mixing here. - create a mixin configuration with attributes, for the
ObjectFactory
to process
It is the ObjectFactory
that learns how you have set up your code and how target classes are extended by mixins classes. The type-paramter DessertTopping
in
Code Block |
---|
var myDessertWax = ObjectFactory.Create<DessertTopping> (ParamList.Empty);
{code}
will have all the information attached to it for the {{ObjectFactory}} to do the right thing and instantiate a _mixed class_, in this case derived from the specified target class {{DessertTopping}} and its mixin. The entirety of all specifications of which mixin classes extend which target classes in an application is called the "mixin configuration" and is determined by reflection when the application starts up ^[determining the mixin configuration]^. The {{ObjectFactory}} knows the entire mixin configuration, usually before any part of your actual application code starts to run.
h5. Putting it all together
By convention, we give a mixin the suffix (wait for it) "Mixin"^["mixin" convention]^. A mixin _requires_ an interface for accessing the mixin's members in the instance, in this case the {{SealFloor}} method.
{code} |
will have all the information attached to it for the ObjectFactory
to do the right thing and instantiate a mixed class, in this case derived from the specified target class DessertTopping
and its mixin. The entirety of all specifications of which mixin classes extend which target classes in an application is called the "mixin configuration" and is determined by reflection when the application starts up determining the mixin configuration. The ObjectFactory
knows the entire mixin configuration, usually before any part of your actual application code starts to run.
Putting it all together
By convention, we give a mixin the suffix (wait for it) "Mixin""mixin" convention. A mixin requires an interface for accessing the mixin's members in the instance, in this case the SealFloor
method.
Code Block |
---|
public interface IFloorWaxMixin
{
void SealFloor ();
}
public class FloorWaxMixin : IFloorWaxMixin
{
public void SealFloor ()
{
Console.WriteLine ("Dirt, grime, even black heel marks -- wipe clean with a damp mop!");
}
}
{code}
|
Now
...
all
...
we
...
have
...
to
...
do
...
for
...
the
...
mixing
...
is
...
telling
...
the
...
DessertTopping
...
class
...
to
...
actually
...
use
...
the
...
FloorWaxMixin
...
class.
...
You
...
do
...
that
...
with
...
the
...
Uses
...
attribute:
...
Code Block |
---|
[Uses (typeof (FloorWaxMixin))]
public class DessertTopping
{
public void TasteGood ()
{
Console.WriteLine ("Mmmmmm, tastes terrific!");
}
}
{code}
|
Here
...
is
...
the
...
call
...
to
...
ObjectFactory
...
again:
...
Code Block |
---|
var myDessertWax = ObjectFactory.Create<DessertTopping> (ParamList.Empty);
{code}
|
You
...
can
...
access
...
DessertTopping
...
's
...
TasteGood
...
as
...
expected:
...
Code Block |
---|
myDessertWax.TasteGood ();
{code}
|
For
...
accessing
...
the
...
FloorWaxMixin
...
's
...
SealFloor
...
you
...
must
...
cast
...
to
...
its
...
interface:
...
Code Block |
---|
((IFloorWaxMixin) myDessertWax).SealFloor ();
{code}
{panel:bgColor=lightgreen}
Brief detour: [Of what class is the instance the object factory returns?]
{panel}
h5. You need only one interface here
Note that the {{DessertTopping}} class does not need an interface, and that the mixin class {{FloorWaxMixin}} does not know anything about the {{DessertTopping}} class. With the {{FloorWaxMixin}} class you can give a {{SealFloor}} method to any class, instantiate it with the {{ObjectFactory}} and call the new instance's {{SealFloor}} method by casting to the {{IFloorWaxMixin}} interface.
h5. A target class can use multiple mixins (of course!)
What if a dessert wax is not useful enough and needs even more features? What about adding a shaving cream for more utility and vitamins to make the dessert wax more nutritious? Make it use more mixins:
{code} |
Panel | ||
---|---|---|
| ||
Brief detour: Of what class is the instance the object factory returns? |
You need only one interface here
Note that the DessertTopping
class does not need an interface, and that the mixin class FloorWaxMixin
does not know anything about the DessertTopping
class. With the FloorWaxMixin
class you can give a SealFloor
method to any class, instantiate it with the ObjectFactory
and call the new instance's SealFloor
method by casting to the IFloorWaxMixin
interface.
A target class can use multiple mixins (of course!)
What if a dessert wax is not useful enough and needs even more features? What about adding a shaving cream for more utility and vitamins to make the dessert wax more nutritious? Make it use more mixins:
Code Block |
---|
[Uses (typeof (FloorWaxMixin))]
[Uses (typeof (ShavingCreamMixin))]
[Uses (typeof (VitaminsMixin))]
public class DessertTopping
{
public void TasteGood ()
{
Console.WriteLine ("Mmmmmm, tastes terrific!");
}
}
{code}
|
Note
...
that
...
each
...
of
...
these
...
mixins
...
also
...
needs
...
an
...
interface,
...
because
...
without
...
one
...
you
...
can't
...
access
...
the
...
mixins
...
member
...
in
...
the
...
instance
...
of
...
the
...
mixed
...
class.
...
For
...
example:
...
Code Block |
---|
myShavingVitaminDessertWax.TasteGood ();
((IFloorWaxMixin) myShavingVitaminDessertWax).SealFloor ();
((IShavingCreamMixin) myShavingVitaminDessertWax).LubricateBeardStubbles ();
((IVitaminsMixin) myShavingVitaminDessertWax).BoostImmuneSystem ();
{code}
h5. |
Don't
...
forget
...
to
...
touch
...
the
...
library
...
As
...
pointed
...
out
...
in
...
the
...
overview
...
...
...
...
...
...
...
...
,
...
you
...
must
...
force
...
the
...
.NET
...
runtime
...
to
...
load
...
a
...
reference
...
to
...
the
...
Remotion.dll
...
assembly.
...
Otherwise
...
the
...
compiler
...
will
...
remove
...
the
...
facilities
...
for
...
loading
...
the
...
Remotion.dll
...
assembly
...
and
...
your
...
application
...
will
...
throw
...
a
...
type
...
initializer
...
exception,
...
because
...
it
...
can't
...
load
...
it.
...
The
...
easiest
...
way
...
to
...
touch
...
the
...
assembly
...
is
...
to
...
use
...
the
...
IMixinTarget
...
identifier:
...
Code Block |
---|
FrameworkVersion.RetrieveFromType (typeof (IMixinTarget));
{code}
You will see this line in all code samples in this tutorial. It doesn't do anything except taking care that the {{Remotion}} assembly can be loaded properly. If you use re-motion mixin in the context of the larger re-motion framework |
You will see this line in all code samples in this tutorial. It doesn't do anything except taking care that the Remotion
assembly can be loaded properly. If you use re-motion mixin in the context of the larger re-motion framework (re-store,
...
for
...
example),
...
you
...
don't
...
need
...
such
...
a
...
line,
...
because
...
the
...
framework
...
will
...
take
...
care
...
of
...
loading
...
the
...
reference.
...
If
...
you
...
forget
...
that
...
line,
...
you
...
will
...
get
...
a
...
...
...
...
.
Using Uses
The sample code presented so far would not be considered in good taste in production. For one, the object factory cannot instantiate the DessertTopping
class independently of its mixin class – the Uses
attribute cannot be ignored here. It is much better style to introduce a dedicated class as target class. A natural name in this example is DessertWax
, using both a DessertTopping
and a FloorWaxMixin
. (Note that we assume here that DessertTopping
can be used as a stand-alone class, not only as a mixin class. For this reason we keep the name DessertTopping
and don't rename it to DessertToppingMixin
, as explained in "mixin" convention.)
What's more, applying the Uses
attribute to the target class is a modification to that target class' source code. It is more practical to do it the other way around and attribute the mixin class with Extends
. The next page explains how this works.
Under the hood
The wiki page under the hood of re-motion mixins -- the simplest case -- 'DessertTopping' uses 'FloorWaxMixin' explains how data is organized for this simple use of re-motion mixins. The data is organized in exactly the same way for what is discussed next – re-motion mixins basics -- the 'Extends' attribute.
Sample code
You can find a complete listing for this dessert wax sample in subversion