Reputation: 7710
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
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
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
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
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