1
public class A {
    public int ID {get;set;}
    public List<int> Things {get;set}
}

public class B : A {
    public string Name {get;set;}
}

public static FillListAThings(ref List<A> lstA){
 // ...
 // code to fill the Things list in each A of lstA with bulk call to database containing all A's IDs from lstA
 // ...
}

public static GetBList(){
  var lstB = new List<B>();

  // ...
  // Fill B list, get IDs and names
  // ...

  // ERROR here, since ref List<B> cannot be converted to a ref List<A>
  FillListAThings(ref lstB); 

}

I can understand not being able to pass a ref List A to a function expecting ref List B, since there would be missing members in the class, but why isn't this possible? I can't cast it as List A through LINQ either, since then it becomes a throw-away variable that can't be referenced.

My current workaround is to cast to a temporary variable of a List A, send that to the function to fill, then copy the properties back to the original list by crossing on their IDs.

// workaround
var tmpListA = lstB.Cast<A>().ToList();
FillListAThings(ref tmpListA);
foreach(var b in lstB)
{
    var a = tmpListA.Where(x => x.ID == b.ID);
    // ... 
    // code to copy properties
    // ...
}
John Cale
  • 13
  • 4
  • Possible duplicate of [Shorter syntax for casting from a List to a List?](https://stackoverflow.com/questions/5115275/shorter-syntax-for-casting-from-a-listx-to-a-listy) – Thomas Weller Jan 19 '18 at 17:16
  • I don't think so, since I'm looking to reference it. The answer on that question states "This casts each item in the list - not the list itself. A new List will be created by the call to ToList()." – John Cale Jan 19 '18 at 17:17
  • The reason is co/contravariance. The second answer in the linked question explains it. The first answer only explains the workaround. – Thomas Weller Jan 19 '18 at 17:18
  • That helped me understand the issue more, but NightOwl888's answer is definitely what I was looking for. Thanks for the help! – John Cale Jan 19 '18 at 17:28

1 Answers1

3

You can, but you need to widen your method signature to accept all List<T> types that implement A, not just List<A> itself.

public static void FillListAThings<T>(ref List<T> lstA) where T : A
{
    // ...
    // code to fill the Things list in each A of lstA with bulk call to database containing all A's IDs from lstA
    // ...
}
NightOwl888
  • 55,572
  • 24
  • 139
  • 212