Home > OS >  Interface logic when a class has parent/child logic
Interface logic when a class has parent/child logic

Time:01-20

I would like to put my interfaces into a separate assembly, but I'm having trouble implementing the interfaces.

public interface IModelObject {...} 

public interface IViewmodel 
{
    IModelObject ModelObject { get; }
}

public interface ITreeNodeViewmodel: IViewmodel {...}

public interface ITreeViewmodel 
{
    ITreeNodeViewmodel Root { get; set; }
}

Now in the implementation:

public class NodeViewmodel:ITreeNodeViewmodel {...}
public class TreeViewmodel:ITreeViewmodel
{
    NodeViewmodel Root { get; set; }

    ITreeNodeViewmodel ITreeViewmodel.Root { get => Root; set => Root = (NodeViewmodel)value; }
    ITreeNodeViewmodel ITreeViewmodel.Root => Root;
}

You can see that the design requires that the TreeViewmodel.Root should be constrained to the NodeViewmodel type. I can explicitly implement the interface and have one smelly explicit cast in the setter.

Is there a better way to enforce a type constraint on this property and still satisfy the interface?

CodePudding user response:

You can create generic interfaces that extend your other interfaces like so

public interface ITreeViewmodel<T> where T: ITreeNodeViewmodel 
{
    T Root { get; set; }
}

CodePudding user response:

There is quite a strong likelihood that you'll end up with this kind of object structure:

public interface IModel
{ }

public interface IViewModel<M> : IModel
    where M : IModel
{
    M Model { get; }
}

public interface ITreeNodeViewModel<M> : IViewModel<M>
    where M : IModel
{ }

public interface ITreeViewModel<M, T>
    where M : IModel
    where T : ITreeNodeViewModel<M>
{
    T Root { get; }
}

public class TreeNodeViewModel<M> : ITreeNodeViewModel<M>
    where M : IModel
{
    public M Model { get; private set; }
}

public class TreeViewModel<M, T> : ITreeViewModel<M, T>
    where M : IModel
    where T : ITreeNodeViewModel<M>
{
    public T Root { get; private set; }
}

I just thought I'd post it as I think it'll be the natural progression of your object model once you start working with it.

CodePudding user response:

Given the requirements you're working with, your implementation looks good. If you don't want a "smelly cast", you could try something along the lines of:

set
{
   if (value is NodeTreeItemViewmodel goodRoot)
   {
      Root = goodRoot;
   }
   else 
   {
      throw new ArgumentException("Root must be a NodeTreeItemViewmodel 
 instance");
   }
}

This takes more code, but will at least give you clearer feedback if something goes wrong.

  •  Tags:  
  • Related