An acting lesson for your pet parrot -- working with 'This'
We have introduced the Parrot
class hierarchy on the wiki-page re-motion mixins basics -- what about sub-classes of the target class?. For the following example we use only the base class, i.e. Parrot
. Note that Parrot
has a Say (string s)
method. (What would a parrot class be without a Say
method?)
public class Parrot { public virtual void Fly () { Console.WriteLine ("Flapflap..."); } public virtual void Whistle () { Console.WriteLine ("<River Kwai March here>"); } public virtual void Say (string s) { Console.WriteLine ("\"{0}\"", s); } }
This natural gift of language can be exploited to teach a parrot how to pretend to have a phone conversation. The mixin class OnThePhoneMixin
and its IOnThePhoneMixin
interface have two methods:
PretendToTalkOnThePhone ()
(usesSay (string s)
)Wait (int milliseconds)
(The Wait
method is important here, because it makes the illusion of a party talking at the other side of the connection more convincing – many stage- and movie actors don't know this, by the way).
By virtue of the Parrot
in the generic Mixin<Parrot>
declaration, the mixin's PretendToTalkOnThePhone
method can access Parrot
's Say
method via the This
property.
The mixin declaration looks like this:
As you see, the class name Parrot
is used twice
- as type parameter for the generic
Mixin<TThis>
base class - as parameter to the
Extends
attribute
It is important not to confuse the two. As parameter for Mixin<TThis>
, Parrot
specifies which properties will be available via This
at compile time. As type for Extends
, Parrot
specifies that the OnThePhoneMixin
mixin extends the Parrot
class.
Usage of the mixed class is straightforward:
// 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: FrameworkVersion.RetrieveFromType (typeof (IMixinTarget)); Console.WriteLine ("Parrot:"); var myPetParrot = ObjectFactory.Create<Parrot> (ParamList.Empty); ((IOnThePhoneMixin) myPetParrot).PretendToTalkOnThePhone (); // how cute! myPetParrot.Whistle (); // back to normal
Sample code
The sample code for this exercise is located in subversion
Alternative: pass the interface
If we had an IParrot
interface with a Say
method, we could also use that interface for the TThis
parameter, because This
would provide access to the IParrot
interface:
Again, the TThis
parameter does NOT influence on which target class the mixin class extends. It specifies where the members visible in This
come from.
What's interesting here is that no connection between IParrot
and Parrot
is required. It does not hurt if Parrot
is declared to actually implement IParrot
, but it is NOT required. It suffices when the methods accessed via the This
property share the same name and signature with those implemented in the target class (as specified in the Extends
attribute, NOT in TThis
parameter).
Matching interface members and This
members is not done via static compilation, it is done by reflection. We will return to this point on the wiki-page re-motion mixins basics -- duck typing.
Sample code
The sample code for the alternative discussed here can be in subversion