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.

2
  • Perhaps you should just use Automapper instead. Commented Feb 2, 2012 at 9:38
  • I have already used it, but team member does not like it for big and nested entities Commented Feb 2, 2012 at 9:40

4 Answers 4

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.

Sign up to request clarification or add additional context in comments.

Comments

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?)

1 Comment

Issue is not with class but Interface, my interface is getting compiled. Changed AddressView to Address
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; }
}

3 Comments

but this does ensure ViewModel
@Lukazoid, yeah I messed up and corrected the code. Now it works.
This is the approach I would go for if I was doing what the asker requiresd
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.

3 Comments

No, This is just an example. My entity contains list of many types. It is not good idea to specify all the types
Why can't your interface just return ICollections? And your implementations return ICollections? Then each implementation can return different implementations of ICollection?
see @oleksii's answer for what I mean, that is what I would go for.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.