1

I am designing an app where similar entities are in two places with different types of collection as following.

Model:

class PersonModel {
  public string Name { get;set;}
  public List<Address> Addresses { get;}
  public List<OtherType> OtherTypes { get;}
}

Similar view model:

class PersonViewModel {
   public string Name { get;set;}
   public ObservableCollection<Address> Addresses { get; }
   public ObservableCollection<OtherType> OtherTypes { get; }
}

To make both entities consistent, I thought use generic interface which ensure both implement all properties, so I created something like this:

public interface IPerson<T> where T: ICollection<T> {
   string Name { get;set;}
   T<Address> Addresses { get;}
   T<OtherType> OtherTypes [ get; } 
}

and classes will be

class PersonModel<List> {}
class personViewModel<ObservableCollection> {}

but compiler not ready to compile my interface. :( Says, the type parameter "T" cannot be used with type argument.

Reason why I want this, i wanted to minimize type conversion from / to model & viewModel.

My viewModel will be like this,

class PersonViewModel<T> : IPerson<T> {
   public PersonViewModel(IPerson model){
      this.Model = model;
   }
   internal PersonModel Entity {
      get; set;
   }
   public string Name { 
      get{ return model.Name;} 
      set {model.Name = value;}
   }
   public T<Address> Addresses {
      get { return model.Addresses.Cast<T>(); }
   }
}

Suggest me better way to have Model & ViewModel synchronized.

hungryMind
  • 6,931
  • 4
  • 29
  • 45

4 Answers4

1

The ViewModel exists to provide data for the View. This means it should be modeled after the requirements of the View. Normally, these requirements are not the same as those for the Model. That means, that normally, your Model and your ViewModel won't be in sync, they will differ. In your approach the ViewModel is not adding any value and could be removed.

To map between the ViewModel and the Model you could use AutoMapper.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
1

Your implementations should look like the following:

class PersonModel : IPerson<List> {}
class PersonViewModel : IPerson<ObservableCollection> {}

Do you really need a generic class? ObservableCollection<T> and List<T> both implement ICollection<T> so you might be able to declare Addresses and OtherTypes in your interface as ICollection<Address> and ICollection<OtherType> respectively.

(what's AddressView?)

vc 74
  • 37,131
  • 7
  • 73
  • 89
0

You cannot use generics in that way. You can try something like this

public interface IPerson
{
    string Name { get; set; }
    ICollection<Address> Addresses { get; }
    ICollection<OtherType> OtherTypes { get; }
}

public class OtherType { }
public class Address { }

And then

class PersonModel : IPerson
{
    public PersonModel()
    {
        Addresses = new List<Address>();
        OtherTypes = new List<OtherType>();
    }

    public string Name { get; set; }
    public ICollection<Address> Addresses { get; private set; }
    public ICollection<OtherType> OtherTypes { get; private set; }
}

class PersonViewModel : IPerson
{
    public PersonViewModel()
    {
        Addresses = new ObservableCollection<Address>();
        OtherTypes = new ObservableCollection<OtherType>();
    }

    public string Name { get; set; }
    public ICollection<Address> Addresses { get; private set; }
    public ICollection<OtherType> OtherTypes { get; private set; }
}
oleksii
  • 35,458
  • 16
  • 93
  • 163
0

Your generic constraint on IPerson is enforcing that T must implement an ICollection of T? That's endlessly recursive which wouldn't be allowed.

You also can't specify generic parameters on generic types, so T<Address> isn't allowed, this is because it is not known whether T is a generic type or not.

You could change your interface to be the following:

public interface IPerson<TAddressCol, TOtherCol> 
   where TAddressCol: ICollection<Address>
   where TOtherCol : ICollection<OtherType> 
{
   string Name { get;set;}
   TAddressCol Addresses { get;}
   TAddressCol OtherTypes [ get; } 
}

Then use it like so:

class PersonModel<List<Address>, List<OtherType>> {}
class personViewModel<ObservableCollection<Address>, ObservableCollection<OtherType>> {}

I think that's the only real way to get the approach you want. But I would suggest that your interface merely returns ICollection<Address> and ICollection<OtherType>. Your model/viewmodel will then have to expose the collections through the interface, however there is nothing stopping you having the backing implementations as List or ObservableCollection respectively.

Lukazoid
  • 19,016
  • 3
  • 62
  • 85
  • No, This is just an example. My entity contains list of many types. It is not good idea to specify all the types – hungryMind Feb 02 '12 at 10:50
  • Why can't your interface just return `ICollection`s? And your implementations return `ICollection`s? Then each implementation can return different implementations of `ICollection`? – Lukazoid Feb 02 '12 at 11:13
  • see @oleksii's answer for what I mean, that is what I would go for. – Lukazoid Feb 02 '12 at 11:17