0

In my unit test I am trying to setup a method to return a List when the actual method expects the return type to me a List. However I am getting this error:

Argument 1: cannot convert from 'System.Collections.Generic.List<FSVendorRepository.AccountingManagement.Models.StatementDetail.RegionalStatementDetailItem>' to 'System.Collections.Generic.List<FSVendorRepository.AccountingManagement.Models.StatementDetail.Base.StatementDetail>'

Which tells me I cannot mock my function to return a List.

Here is the code:

Base class:

namespace FSVendorRepository.AccountingManagement.Models.StatementDetail.Base {
    public abstract class StatementDetail {
              //Props
    }
}

Derived class:

namespace FSVendorRepository.AccountingManagement.Models.StatementDetail {
    public class RegionalStatementDetailItem : Base.StatementDetail {
              //Props
    }
}

Interface:

namespace FSVendorRepository.AccountingManagement {
    public interface IAccountingManager {
        List<StatementDetail> ReturnDerivedListTest();
        StatementDetail ReturnDerivedClassTest();

    }
}

Unit test:

 public async Task ReturnStatementDetails_UserIsMasterSubRepAndIsExporting_CorrectRegionalStatementDetailsClassReturned() {
            var regionalItem = new RegionalStatementDetailItem();
            var liRegionalItems = new List<RegionalStatementDetailItem>();

            _iMockAccountingManager.Setup(x => x.ReturnDerivedListTest()).Returns(liRegionalItems); //compile time exception
            _iMockAccountingManager.Setup(x => x.ReturnDerivedClassTest()).Returns(regionalItem); //passes
}

I'm doubly confused when i created a method which returns a single instance of the base class and substituted it with the derived class and it worked.

Why doesn't think work?

Andrew
  • 720
  • 3
  • 9
  • 34
  • 2
    read about covariance and contravariance https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance/ – MistyK Mar 15 '18 at 22:31
  • Why you can't ? Because, if you return a List, then this list must receive only DerivedClass. But a List could also receive OtherDerivedClass . So you can do *less* things with List compared to List (But you can do *more* things with DerivedClass compared to BaseClass) That's why the conversion can't be made simply by the compiler this way. These things are called covariance and contravariance. – Pac0 Mar 15 '18 at 22:43

1 Answers1

2

Because List<DerivedClass> does not derive from List<BaseClass> and the fact that the T inside does is irrelevent when looking at it from that perspective.

What you're looking for is Covariance. There's MSDN documentation on it here: https://learn.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance

McAden
  • 13,714
  • 5
  • 37
  • 63
  • `it can't magically know that the T inside does.` Of course both the compiler as well as the runtime know. That is not the problem. You cannot treat a List like a List, because otherwise you could add flowers to your list of dogs, which of course doesn't make much sense (unless flowers are dogs...), hence the error... –  Mar 15 '18 at 22:38
  • Edited for clarity – McAden Mar 15 '18 at 22:40