Aaginor
Aaginor

Reputation: 4782

How to set a derived object to a base class variable when the baseclass is generic

in my Silverlight 4 application, I am trying to use generics, but there is another problem, that I hope to solve with the help of the stackoverflow-community:

I have a Tree-Structure, that can have two modes, Editor-mode, where the tree is created, nodes added, moved, deleted etc. and a Configurator-mode, where the user can i.e. select nodes of the tree.

To represent the tree, I created a base class for both modes, and a derived class for each mode. As the Editor-mode can only have Editor-Nodes and the Configurator-Mode can only have Configurator-Nodes, I made the baseclass generic:

public abstract class ServiceModelBase<TRootNodeType>
    where TRootNodeType : ServiceNodeVMBase
{
  public TRootNodeType RootNode
  {
    get { return _rootNode; }
  }
  ...
}

public class ServiceModelConfigurator : ServiceModelBase<ServiceNodeVMConfigurator>
public class ServiceModelEditor : ServiceModelBase<ServiceNodeVMEditor>

Both ServiceNodeVMConfigurator and ServiceNodeVMEditor inheriting from ServiceNodeVMBase

The application can save and load the saved data. Loading works (in short) this way:
1.) Deserialize the serialized data in a special Datatransferobject.
2.) Depending on the type of the Datatransferobject, creating a ServiceModelConfigurator or ServiceModelEditor
3.) Firing an event, that contains (beside others) the created ServiceModel

I have created a class derived from EventArgs that have to store the ServiceModel. As this ServiceModel can be Editor or Creator, I declared the Property to store it of the baseclasstype:

public class ServiceModelLoadedEventArgs : EventArgs
{
  public ServiceModelBase<ServiceNodeVMBase> ServiceModel;
  ...
}

But unfortunatly, I cannot assign the derived ServiceModelEditor/Configurator to the EventArgs ServiceModel variable:

ServiceModelLoadedEventArgs args = new ServiceModelLoadedEventArgs();
args.ServiceModel = new ServiceModelEditor();

The compiler tells me, that it cannot convert ServiceModelEditor in ServiceModelBase

Can anyone tell me, how I have to write the code for the EventArgs-class that I can assign a ServiceModelEditor or ServiceModelConfigurator to the ServiceModel variable?

PS: I want to apologize that this is just another generics related question from me, but I fear generics and me are not really friends yet.

Upvotes: 1

Views: 435

Answers (2)

phoog
phoog

Reputation: 43046

To use covariance you'll have to declare a covariant interface:

public interface IServiceModelBase<out TRootNode> 
     where TRootNode : ServiceNodeVMBase 
{ 
    TRootNode RootNode { get; }     
} 

public abstract class ServiceModelBase<TRootNode> : IServiceModelBase<TRootNode>
{
    ...
}

public class ServiceModelLoadedEventArgs : EventArgs   
{   
  public IServiceModelBase<ServiceNodeVMBase> ServiceModel { get; set; }  
  ...   
}   

public class ServiceModelEditor : ServiceModelBase<ServiceNodeVMEditor>  

And:

ServiceModelLoadedEventArgs args = new ServiceModelLoadedEventArgs();        
args.ServiceModel = new ServiceModelEditor();

Upvotes: 1

Yochai Timmer
Yochai Timmer

Reputation: 49251

You can use co-variance:

public abstract class ServiceModelBase<out RootNodeType>
     where RootNodeType : ServiceNodeVMBase
{


}

Upvotes: 0

Related Questions