Tom Fischer

  Home  |   Contact  |   Syndication    |   Login
  21 Posts | 0 Stories | 44 Comments | 0 Trackbacks

News

Archives

Post Categories

.NET Framwork

TFS

Tools

Visual Studio

After being in TFS-Land for a couple of months and celebrating the birth of my second daughter, I finally had time to go back to do some C# coding. Hurray!

Then, I ran into an interesting issue:
When you derive from a class which has an interface implemented you cannot just override the implement methods again. Even if you use the new keyword breaks when you cast the instance to the interface type, you might not achieve the desired result.

Let's look at a quick example and deal with solutions afterwards:

public interface ITom
{
    string IdeaOfTheDay();
}

public class BaseClass : ITom
{
    public string IdeaOfTheDay()
    {
        return "Base Idea";
    }
}

public class DerivedClass : BaseClass
{
    //I have to use the new keyword
    public new string IdeaOfTheDay()
    {
        return "New Idea";
    }
}


DerivedClass d = new DerivedClass();
Console.WriteLine(d.IdeaOfTheDay());
//Writes: New Idea

ITom t = d as ITom;
Console.WriteLine(t.IdeaOfTheDay());
//Writes: Base Idea  -> oops not what I hoped for

Okay this shouldn't have come as a surprise to me. When I thought about it for a second, I realized it is standard polymorphism with contracting to a specific non virtual method. Using interfaces made me forget this for a second.

If we didn't have interaces and we could not change the BaseClass to virtual or make the BaseClass abstract,  we would be done here. Even using the new keyword does not work if we cast to an interface, because the actual contract is with the BaseClass.
Pretty bad when you deal with customer dlls where you cannot modify the source code.

Cheating Polymorphism with Interfaces in an emergency

But with interfaces there is one more thing you can do if you can not change the BaseClass:
Just re-implement the Interface!
public class BaseClass : ITom
{
   
public string IdeaOfTheDay()
    {
       
return "Base Idea";
    }
}

public class DerivedClass : BaseClass, ITom
{
   
//We still need the keyword
   
public new string IdeaOfTheDay()
    {
       
return "New Idea";
    }
}


DerivedClass d =
new DerivedClass();
Console.WriteLine(d.IdeaOfTheDay());
//Writes: New Idea

ITom t = d
as ITom;
Console.WriteLine(t.IdeaOfTheDay());
//Writes: New Idea NOT: Base Idea anymore

Kind of messy but this can be a lifesaver!

Using Polymorphism correctly with Interfaces

But if you can modify the BaseClass you definitely want to use virtual methods.

Even though Interfaces are not virtual by nature, you can still declare the method virtual in your class implementation and make them virtual!
This gives you the best out of both worlds: Polymorphism from Inheritance and Contracting via Interfaces.

public class BaseClass : ITom
{
    public virtual string IdeaOfTheDay()
    {
        return "Base Idea";
    }
}

public class DerivedClass : BaseClass{
    //normal overriding
    public override string IdeaOfTheDay()
    {
        return "New Idea";
    }
}


DerivedClass d = new DerivedClass();
Console.WriteLine(d.IdeaOfTheDay());
//Writes: New Idea

ITom t = d as ITom;
Console.WriteLine(t.IdeaOfTheDay());
//Writes: New Idea NOT: Base Idea anymore

Think about it: An interace is just a contract! Nothing more, nothing less!

Tom

posted on Monday, November 24, 2008 10:04 AM

Feedback

# re: C# Cheating Polymorphism: Interfaces are not virtual by nature, or are they? 1/3/2009 4:39 PM Andy
Nice example, thanks for posting.

A question: Is it possible to have an abstract base class that implements an interface in an abstract fashion? More precisely, can you declare the interface methods as abstract, or do they have to be marked as virtual?

i.e. can you do this:
public abstract class BaseClass : ITom
{
public abstract string IdeaOfTheDay();
}


# re: C# Cheating Polymorphism: Interfaces are not virtual by nature, or are they? 2/26/2009 2:50 PM David
I like this one better:
------------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestSomething
{
class Program
{
static void Main(string[] args)
{
List<ITom> list = new List<ITom>();
list.Add(BaseClass<DerivedClass>.Singleton as ITom);
list.Add(BaseClass<AmazingIdea>.Singleton as ITom);
foreach(ITom instance in list)
{
Console.WriteLine(instance.IdeaOfTheDay());
}
}
}
public interface ITom
{
string IdeaOfTheDay();
}
public class BaseClass<T>: ITom where T : ITom
{
static BaseClass<T> _instance = _instance = Activator.CreateInstance(typeof(T)) as BaseClass<T>;
public virtual string IdeaOfTheDay()
{
return "Base Idea";
}
public static BaseClass<T> Singleton
{
get
{
return _instance;
}
}
}
public class DerivedClass : BaseClass<DerivedClass>
{
public override string IdeaOfTheDay()
{
return "New Idea";
}
}
public class AmazingIdea : BaseClass<AmazingIdea>
{
public override string IdeaOfTheDay()
{
return "this is an amazing idea!";
}
}
}


# re: C# Cheating Polymorphism: Interfaces are not virtual by nature, or are they? 2/26/2009 2:57 PM David
type in previous post's main method. here's the correct code:

you can see the singleton caller doesn't need any casting, it's just returning an ITom interface.

------

static void Main(string[] args)
{
List<ITom> list = new List<ITom>();
list.Add(BaseClass<DerivedClass>.Singleton);
list.Add(BaseClass<AmazingIdea>.Singleton);
foreach(ITom instance in list)
{
Console.WriteLine(instance.IdeaOfTheDay());
}
}

---

The Singleton static property in the base class changes to this:

public static ITom Singleton
{
get
{
return _instance;
}
}

# re: C# Cheating Polymorphism: Interfaces are not virtual by nature, or are they? 2/26/2009 3:03 PM David
I would actually make the base class abstract and the work method abstract too.

Here's the entire program written correctly:
--------------------------------------------------

using System;
using System.Collections.Generic;

namespace TestSomething
{
class Program
{
static void Main(string[] args)
{
List<ITom> list = new List<ITom>();
list.Add(BaseClass<DerivedClass>.Singleton);
list.Add(BaseClass<AmazingIdea>.Singleton);
foreach(ITom instance in list)
{
Console.WriteLine(instance.IdeaOfTheDay());
}
}
}
public interface ITom
{
string IdeaOfTheDay();
}
public abstract class BaseClass<T>: ITom where T : ITom
{
static BaseClass<T> _instance = _instance = Activator.CreateInstance(typeof(T)) as BaseClass<T>;
public abstract string IdeaOfTheDay();
public static ITom Singleton
{
get
{
return _instance;
}
}
}
public class DerivedClass : BaseClass<DerivedClass>
{
public override string IdeaOfTheDay()
{
return "New Idea";
}
}
public class AmazingIdea : BaseClass<AmazingIdea>
{
public override string IdeaOfTheDay()
{
return "this is an amazing idea!";
}
}
}


# re: C# Cheating Polymorphism: Interfaces are not virtual by nature, or are they? 2/26/2009 3:04 PM David
I would actually make the base class abstract and the work method abstract too.

# re: C# Cheating Polymorphism: Interfaces are not virtual by nature, or are they? 2/26/2009 3:12 PM David
here's another example of using the api from your main:
-----------------------------------------------------------------

static void Main(string[] args)
{
ITom tom = BaseClass<DerivedClass>.Singleton;
Console.WriteLine(tom.IdeaOfTheDay());
Console.WriteLine(BaseClass<AmazingIdea>.Singleton.IdeaOfTheDay());
}

Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: