Ucodia
Ucodia

Reputation: 7710

How to call derived class virtual method?

I created these classes:

public abstract class Node
{
    public virtual NodeModel CreateModel()
    {
        throw new NotImplementedException();
    }
}

public class Folder : Node
{
    public virtual FolderModel CreateModel()
    {
        // Implementation
    }
}

public class Item : Node
{
    public virtual ItemModel CreateModel()
    {
        // Implementation
    }
}

Then in my program I have a List of Node which only contains Item and Folder objects. When I loop on the list and try to call the CreateModel() method, this is always the Node class method which is called (therefore throwing the exception).

I cannot change CreateModel() to abstract as the return type is different depending on the derived type. I was wondering if it is possible to have a different return type. I also want to avoid generics. The fact is that Intellisense is showing me the upper class method when playing around with an instance of it. If I remove the virtual implementation from the upper class, then it displays the base class implementation. This is where I thought it is actually possible.

So how can I force the program to call the upper class method?


EDIT: The answer was actually simple and was right under my nose. The return type does not matter as it will inherits from the return type defined in the base class abstract CreateModel(). I just marked the method as abstract in my base class and it works just fine. I don't know why I got confused at some moments because now it seems pretty obvious to me.

Thanks everybody for helping me out.

Upvotes: 1

Views: 2184

Answers (4)

Anand
Anand

Reputation: 757

public abstract class Node
{
    public virtual NodeModel CreateModel()
    {
        throw new NotImplementedException();
    }
}

public class Folder : Node
{
    public virtual FolderModel CreateModel()
    {
        // Implementation
    }
}

This is not method overriding but it's over loading.

Node node=new Folder();
node.CreateModel();//Of Folder 

To do this you have to override CreateModel in derived(Folder) class

Upvotes: 0

Serge Wautier
Serge Wautier

Reputation: 21878

Here's a version where class inheritance is used instead of generics:

public abstract class Node 
{ 
    public virtual NodeModel CreateModel() 
    { 
        throw new NotImplementedException(); 
    } 
} 

public class FolderModel : NodeModel
{
  // blah
}

public class Folder : Node 
{ 
    public virtual NodeModel CreateModel() 
    { 
      var node = new FolderModel();
      blah;
      return node; // FolderModel derives from NodeModel
    } 
} 

public class ItemModel : NodeModel
{
  // blah
}

public class Item : Node 
{ 
    public virtual NodeModel CreateModel() 
    { 
      var node = new ItemModel();
      blah;
      return node; // ItemModel derives from NodeModel
    } 
} 

public foo(Node node)
{
  var model = node.CreateModel();
}

The type of model depends on type of node. Manipulating the specific parts of the model must somehow be part of virtual node methods that know the inners of each specific model.

Upvotes: 0

Ozan
Ozan

Reputation: 4415

C# does not support covariance in function return types.

Anyway, you only need to specify the return type of CreateModel() as something else than NodeModel when other parts are relying on them to be more specific, e.g. when FolderModel extends NodeModel with more methods.

If you are only iterating over a list of Node objects and call CreateModel() it is not needed, just declare Folder.CreateModel() with NodeModel return type, even though it returns a FolderModel.

Upvotes: 1

Jon Skeet
Jon Skeet

Reputation: 1500425

It looks to me like your base class should be generic, with your derived classes specifying the appropriate type argument.

public abstract class Node<T> where T : NodeModel
{
    public abstract T CreateModel();
}

public class Folder : Node<FolderModel>
{
    public override FolderModel CreateModel()
    {
        // Implementation
    }
}

public class Item : Node<ItemModel>
{
    public override ItemModel CreateModel()
    {
        // Implementation
    }
}

Now you have a single method, overridden appropriately - instead of method hiding which was always going to get confusing.

EDIT: If you want to be able to refer to these without generics, you could always create a non-generic interface, like this:

public interface INode
{
    NodeModel CreateModel();
}

public abstract class Node<T> : INode where T : NodeModel
{
    public abstract T CreateModel();

    // Explicit interface implementation so we can implement INode.CreateModel
    // with a different return type. Just delegate to the strongly-typed method.
    NodeModel INode.CreateModel()
    {
        return CreateModle();
    }
}

Upvotes: 2

Related Questions