This is a mirror of official site: http://jasper-net.blogspot.com/

Implementing the virtual method pattern in C#, Part Two

| Tuesday, March 22, 2011
So far we've gotten rid of instance methods; they're just static methods that take a hidden "this" parameter. But virtual methods are a bit harder. We're going to implement virtual methods as fields of delegate type containing delegates to static methods.

abstract class Animal
{
  public Func<Animal, string> Complain;
  public Func<Animal, string> MakeNoise;
  public static string MakeNoise(Animal _this)
  {
    return "";
  }
}

OK, everything seems fine so far...

class Giraffe : Animal
{
  public bool SoreThroat { get; set; }
  public static string Complain(Animal _this)
  {
    return _this.SoreThroat ? "What a pain in the neck!" : "No complaints today.";
  }
}

Trouble. "Animal" does not have a property SoreThroat. But Complain cannot take a Giraffe, because then it is not compatible with the delegate type, which after all, expects an Animal as the "_this" formal parameter.

What we need to make the virtual method pattern work is a guarantee that the caller will never pass in a Cat to a "virtual" method that is expecting a Giraffe. Let's assume that we have such a guarantee. Since we have that guarantee, we can make a conversion:

class Giraffe : Animal
{
  public bool SoreThroat { get; set; }
  public static string Complain(Animal _this)
  {
    return (_this as Giraffe).SoreThroat ? "What a pain in the neck!" : "No complaints today.";
  }
}
class Cat : Animal
{
  public bool Hungry { get; set; }
  public static string Complain(Animal _this)
  {
    return (_this as Cat).Hungry ? "GIVE ME THAT TUNA!" : "I HATE YOU ALL!";
  }
  public static string MakeNoise(Animal _this)
  { 
    return "MEOW MEOW MEOW MEOW MEOW MEOW";
  }
}
class Dog : Animal
{
  public bool Small { get; set; }
  public static string Complain(Animal _this)
  {
    return "Our regressive state tax code is... SQUIRREL!";
  }
  public static string MakeNoise(Dog _this)  // Remember, we forgot to say "override"
  { 
    return _this.Small ? "yip" : "WOOF"; 
  }
}

Everything good? Not yet. We forgot to initialize the fields!

Here for the first time we come to something that you actually cannot do in "C# without instance methods". In the CLR, the virtual method "fields" are actually initialized after the memory allocator runs but before the constructor runs. (*) We have no way in C# of doing that. So let's go crazy here; we've already gotten rid of instance methods; instance constructors are basically just instance methods that are called when the object is created. So let's get rid of instance constructors too. Instead, instance constructors will be replaced by the factory pattern, where a static method creates and initializes the object. (We presume that this static method has the powers of a constructor; for example it is allowed to set readonly fields, and so on.) A call to a default constructor now does nothing but allocate memory.

Posted via email from Jasper-net

0 comments: