Generic interface implementation confusion

Viewed 96

I'm getting myself in a bit of a mess regarding interface implementations, all my attempted 'fixes' seem to make the whole solution more complex and broken. I'm sure there is a simple answer, but I can't quite see it at the moment!

I have these two interfaces (the second is used in a list of the first):

public interface IUserDefinedListEditViewModel<T> where T : IUserDefinedListEntryEditViewModel<IBaseUserDefinedListModel>
{
    string TypeName { get; set; }
    IList<T> UserDefinedListEntries { get; set; }
}

public interface IUserDefinedListEntryEditViewModel<T> where T : IBaseUserDefinedListModel
{
    string Display { get; set; }
    T UserDefinedListEntry { get; set; }
}

I have a third interface which is implemented by several different classes:

public interface IBaseUserDefinedListModel
{
    Guid Id { get; set; }
    string Name { get; set; }
    bool IsSystem { get; set; }
}

Below is my (incorrect) implementation attempt:

public class APEditViewModel : IUserDefinedListEditViewModel<APEntryEditViewModel>
{
    public string TypeName { get; set; }
    public IList<APEntryEditViewModel> UserDefinedListEntries { get; set; } = new List<APEntryEditViewModel>();
}

public class APEntryEditViewModel : IUserDefinedListEntryEditViewModel<APModel>
{
    public string Display { get; set; }
    public APModel UserDefinedListEntry { get; set; }
}

public class BaseUserDefinedListModel : IBaseUserDefinedListModel
{
    public Guid Id { get; set; }
    [Required(ErrorMessage = "The Name field is required.")]
    public string Name { get; set; }
    public bool IsSystem { get; set; }
}

public class APModel : BaseUserDefinedListModel
{
    public string NewValue { get; set; }
}

The main error I'm getting at the moment is in the APEditViewModel, here is the (cut down) error:

The type 'APEntryEditViewModel' cannot be used as type parameter 'T' in the
generic type or method 'IUserDefinedListEditViewModel<T>'. There is no 
implicit reference conversion from 'APEntryEditViewModel' to 
'IUserDefinedListEntryEditViewModel<IBaseUserDefinedListModel>'.

I'm not sure whether I need this level of generic interfaces, but from my research and experiments, I believe I do. I'm just not quite getting there and I'm thinking that the IUserDefinedListEditViewModel interface needing a type in the type interface (IUserDefinedListEntryEditViewModel) seems wrong.

Sorry that I'm not making myself that clear, it's quite tricky to explain because I'm not sure where I'm going wrong, so any questions I'll try and answer/update my question.

2 Answers

Change your IUserDefinedListEditViewModel interface to:

public interface IUserDefinedListEditViewModel<T1,T2> 
           where T1 : IUserDefinedListEntryEditViewModel<T2> 
           where T2 : IBaseUserDefinedListModel

After that, and update the implementation in APEditViewModel:

public class APEditViewModel : IUserDefinedListEditViewModel<APEntryEditViewModel, APModel>

The error indicates that with the generic constraint

where T : IUserDefinedListEntryEditViewModel<IBaseUserDefinedListModel>

only IUserDefinedListEntryEditViewModel<IBaseUserDefinedListModel> and types which implement this interface will be accepted as T. If you want any IBaseUserDefinedListModel to be accepted in the type parameter of T, you need to make it generic as well.

You need to give us the whole business scenario for expecting the right design suggestions.

As of above examples the issue is: Your defined interface::

interface IUserDefinedListEditViewModel<T> where T : IUserDefinedListEntryEditViewModel<IBaseUserDefinedListModel>

But while calling you are passing APEntryEditViewModel as Interface specific type. Which is wrong with OOPS.

To successfully compile this your

APEntryEditViewModel must be an implimentation of IUserDefinedListEntryEditViewModel

Related