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.
