IntoTheBlue
IntoTheBlue

Reputation: 199

C# Generics - can this be done better?

I am trying to get my head around Generics and am refactoring an existing class. I would appreciate feedback on whether it could be done better.

I have a number of ViewModels which implement similar behaviour and could be derived from a common class. An example would be:

public class SelectSupplierViewModel : SelectViewModel<SupplierAModel>

SupplierAModel is an ISelectModel.

The following class enables a view which displays a menu of items to work with multiple types of data

public class SelectViewModel<T> : ViewModelBase where T : ISelectModel
{
  public Action<SelectViewModel<T>> OnItemSelected;

  public IEnumerable<T> Selections { get; set; }  

  public T SelectedItem
  {
      get { return null; }
      set {
          RaisePropertyChanged();
          OnItemSelected?.Invoke(this);
      }
  }

  .
  .
  .

OnItemSelected is hooked up to a handler in a separate class. It is executed on the earlier 'Invoke':

private void OnSupplierSelected(SelectViewModel<SelectAModel> viewModel)
{
    // When I inspect viewModel I can see that viewModel is a 
    // SelectSupplierViewModel, and I need to access properties on 
    // this.

    // Is it possible to do so without casting viewModel to    
    // SelectSupplierViewModel?
}

It was not possible to have a method accepting a SelectSupplierViewModel as the SelectViewModel class is expecting SelectViewModel.

Thankyou!

Upvotes: 1

Views: 122

Answers (1)

Good Night Nerd Pride
Good Night Nerd Pride

Reputation: 8452

You could add the deriving type to the type parameters of SelectViewModel<> like so:

public class SelectViewModel<TModel, TViewModel> : ViewModelBase 
    where TModel : ISelectModel, TViewModel: SelectViewModel<TModel, TViewModel>
{

Note that you have to add a generic type constraint for TViewModel so you can cast this to TViewModel when invoking the event handler.

Use TViewModel for your event declaration:

public Action<TViewModel> OnItemSelected;

...and for its invocation:

OnItemSelected?.Invoke((TViewModel)this);

Deriving from the new base class is similar -- just add the type you are about to declare to the type parameter list:

public class SelectSupplierViewModel 
    : SelectViewModel<SupplierAModel, SelectSupplierViewModel>
{

Here is a working example: https://dotnetfiddle.net/8gHBwj

Upvotes: 2

Related Questions