C# .NET MVC 5 DisplayTemplate dla IListy interfejsów.

0

Drodzy Koledzy,
przede wszystkim pragnę się powitać, bo to mój pierwszy post :)

Problem mam następujący - mam interfejs, klasę implementującą interfejs oraz klasę dziedziczącą klasę implementującą interfejs. Wygląda to tak:

public class SlownikBazowyVm : ISlownikBazowy
    {
        public int? Id { get; set; }
        public string Wartosc { get; set; }
        public bool Aktywny { get; set; }
        public int? Kolejnosc { get; set; }
    }
 
    public interface ISlownikBazowy
    {
        int? Id { get; set; }
 
        string Wartosc { get; set; }
 
        bool Aktywny { get; set; }
 
        int? Kolejnosc { get; set; }
    }
 
    public class SlownikSzczegolowyVm : SlownikBazowyVm
    {
 
    }

Chcę przygotować display template do takiego pola: IList<SlownikSzczegolowyVm>. W display template mam zdefiniowany model: @model IList<ISlownikBazowy>
Nad polem mam podanego UIHinta do odpowiedniego pliku .cshtml. Jednak próba wykonania tego kodu kończy się wyjątkiem: "The model item passed into the dictionary is of type 'System.Collections.Generic.List1[SlownikSzczegolowyVm]', but this dictionary requires a model item of type 'System.Collections.Generic.IList1[ISlownikBazowy]'.".
Gdyby nie była to lista to zadziałałoby poprawnie, co właśnie sprawdziłem. Nie rozumiem jednak dlaczego program rzuca wyjątkiem skoro podaję do displaytemplate obiekt implementujący interfejs.
Z góry dziękuję za wskazówki i pozdrawiam.

PS: Mam nadzieję, że formatowanie jest ok, podpierałem się instrukcją: Formatowanie treści postów na forum

2

Spróbuj użyć IEnumerable zamiast IList, IEnumerable jest kowariancyjne.

0

Rzeczywiście, działa prawidłowo. Nie rozumiem jednak dlaczego. Co to znaczy, że IEnumerable jest kowariancyjne?

4

Zobaczmy na definicję :
public interface IEnumerable< out T>
public interface IList<T>

w IEnumerable przed T masz słówko out, które mówi że typ jest kowariancyjny, czyli zamiast typu bazowego możesz użyć dowolny typ pochodny, w IList nie masz tego słówka out, więc T jest niezmienny/invariant.

Dlaczego IList nie jest kowariancyjny? Bo w przeciwieństwie do IEnumerable umożliwia dodawanie elementów i gdyby był kowariancyjny to by był problem:

class Gruszka dziedziczy po Owoc
class Sliwka dziedziczy po Owoc

var gruszki= new List<Gruszka>();
IList<Owoc> foo = gruszki;
foo.Add(new Sliwka());      // aaaaa tak nie wolno!

bo moglibyśmy dodać do listy "gruszek" elementy które nie są gruszkami :D

Jako ciekawostka tablice w C# są kowariancyjne, ale jest to błąd, skopiowany z Javy.

0

No widzisz, nie wiedziałem o tym. Znalazłem też rozdział w dokumentacji na ten temat - jednak dopiero po tym jak wiedziałem czego szukać :D - https://docs.microsoft.com/pl-pl/dotnet/csharp/language-reference/keywords/out-generic-modifier I dla dociekliwych link do artykułu o kowariancji i kontrawariancji: https://docs.microsoft.com/pl-pl/dotnet/csharp/programming-guide/concepts/covariance-contravariance/index

Czy dobrze rozumiem, że w tym kontekście out oznacza zupełnie co innego niż out używane przy przekazywaniu parametrów funkcji przez referencję?

1 użytkowników online, w tym zalogowanych: 0, gości: 1