Search code examples
c#genericscontravariancevariance

Contravariance in Generics C#


I don't know who resolve this segment code with variance:

I have an abstract father class:

public abstract class PdfObject
{...}

And two child classes:

public class PdfText : PdfObject
{...}

public class PdfImage : PdfObject
{...}

Now, my wrong or empiric code is the next:

public IList<PdfText> GetTexts()
{
       List<PdfText> result = new List<PdfText>();
       List<PdfObject> list = GetList();
       foreach(var item in list)
       {
           if(item is PdfText) result.Add(item)
       }
       return result;
} 

public List<PdfObject> GetList()
{...}

Well, i read a lot of this theme, but don't stand how use variance in generics or use a better solution for this issue.

Please, help me and thanks.


Solution

  • This doesn't have much to do with variance, directly. Your problem is here:

    public IList<PdfText> GetTexts()
    {
        List<PdfText> result = new List<PdfText>();
        List<PdfObject> list = GetList();
        foreach(var item in list)
        {
            if(item is PdfText) result.Add(item)
        }
        return result;
    } 
    

    The static type of the item variable is PdfObject so you cannot add it to result; you need to cast it. For example

    if (item is PdfText) result.Add((PdfText)item);
    

    This is inefficient because you check the type twice: once for the is operator and once for the cast. Instead, you're supposed to do this:

    public IList<PdfText> GetTexts()
    {
        List<PdfText> result = new List<PdfText>();
        List<PdfObject> list = GetList();
        foreach(var item in list)
        {
            var textItem = item as PdfText
            if (textItem != null) result.Add(textItem)
        }
        return result;
    } 
    

    Or, you can use linq:

    var result = GetList().OfType<PdfText>().ToList();