Search Unity

Converting List<class> to List<interface>

Discussion in 'Scripting' started by vee41, May 30, 2015.

  1. vee41

    vee41

    Joined:
    Nov 14, 2013
    Posts:
    32
    Hi!

    I am in situation where I'd like to display various stuff on my UI. I'm struggling a bit what would be a nice, generic way to transfer data from my various classes to UI elements that display things.

    My current idea is to have data elements implement interface IListable, which in turn offers functions UI elements can use to populate themselves with data assigned to them.

    i.e:

    Code (CSharp):
    1. Class Man : IListable {
    2. public string Display name() {}
    3.  
    4. }
    Code (CSharp):
    1. Class Tree: IListable {
    2. public string Display name() {}
    3.  
    4. }
    To display these classes in UI element the element would need

    Code (CSharp):
    1. Class UIList {
    2. List<IListable> content;
    3.  
    4. public void Draw() {
    5.  
    6. // draw each element in content list
    7.  
    8. }
    9.  
    10. public void SetContent(List<Man> content) {
    11.  
    12. // SetContent as specific list of elements
    13. this.content = content; <---- Can't do this
    14.  
    15. }
    16.  
    17. }
    Now the issue is I'd like to just toss one of my classes to the UIList class and have it access that class through the IListable interface in nice generic way. But I cannot find simple non loopy way to do List<Interface> stuff = List<ClassThatImplementsInterface>. Is there a way to do this, or some other way I should approach this?
     
  2. eisenpony

    eisenpony

    Joined:
    May 8, 2015
    Posts:
    974
    A List is an example of a type of object called a variant. It is called a variant because it creates a "variation" of the basic type it is a list for. Variants are interesting when mixed with inheritance because they can modify the inheritance direction. If you're interested in that stuff, you can look up covariance and contravariance.

    Anyways.. In your case, you are trying to do something that is technically allowed but you need to be a little more explicit because the compiler doesn't like to make assumptions about variants.

    You have three options:

    Code (csharp):
    1. class UIList{
    2.   List<IListable> content = new List<IListable>();
    3.  
    4.   public void SetContent(List<Man> content)
    5.   {
    6.     this.content.AddRange(content);
    7.   }
    8. }
    or

    Code (csharp):
    1. class UIList{
    2.   List<IListable> content;
    3.   public void SetContent(List<Man> content)
    4.   {
    5.     this.content = content.Cast<IListable>().ToList();
    6.   }
    7. }
    or

    Code (csharp):
    1. class UIList{
    2.   List<IListable> content = new List<IListable>();
    3.   public void SetContent(List<IListable> content)
    4.   {
    5.     this.content = content;
    6.   }
    7. }
    The basis of all three options is that you need to tell the compiler to cast each item inside of the variant rather than trying to cast the whole variant at once.
     
    vee41 likes this.
  3. vee41

    vee41

    Joined:
    Nov 14, 2013
    Posts:
    32
    Thank you for the detailed explanation, exactly what I was looking for! That makes total sense when you present it in simple way like that :)

    In case anyone else runs into this in future : you'll need to add "using System.Linq", otherwise casting does not seem to work.