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 () (uses Say (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

Under the hood