-1

I am new to C# and seem to be stuck at a problem. The return type of the function ThreeSum called is IList<IList> and the List being returnted is of type List<List> and I am seeing the following exception: Cannot implicitly convert type 'System.Collections.Generic.List<System.Collections.Generic.List>' to 'System.Collections.Generic.IList<System.Collections.Generic.IList>'.

Here is the code:

public IList<IList<int>> ThreeSum(int[] nums) 
{
    Array.Sort(nums);
    var result = new List<List<int>>();
    for (int i = 0; i < nums.Length; i++)
    {
        if (nums[i] > 0) break;
        twoSum(nums, i, result);
    }
    return result;
}
private void twoSum(int[] nums, int i, List<List<int>> result)
{
    var seen = new HashSet<int>();
    for (int j = i + 1; j < nums.Length; j++)
    {
        int comp = -nums[i] - nums[j];
        if (seen.Contains(comp))
        {
            result.Add(new List<int>(){nums[i], nums[j], comp});
        }
        while (j < nums.Length - 1 && nums[j] == nums[j+1]) j++;
    }
}
Caius Jard
  • 72,509
  • 5
  • 49
  • 80
Dev
  • 1
  • 1
  • Consider a case where you have 3 implementations of `IList`, plain `List`, `ReadOnlyList` and `LeftHandedList`. All are obviously convertible to `IList`. So you could create one of the specialized lists, cast it to an IList, and the cast it to one of the other implementations – Flydog57 Jan 30 '22 at 02:57
  • 1
    Imagine you have an object of `List` and you would be allowed to cast it to `IList>`. Someone could then try inserting a `ArraySegment` which *is* a `IList` but is *not* a `List`. So this could never be allowed. You could cast to `IReadOnlyList>` because that is covariant and therefore assignment-compatible – Charlieface Jan 30 '22 at 03:10

2 Answers2

2

You can

var result = new List<IList<int>>();

and then make sure that whatever you put in your result list implements IList, such as:

result.Add(new List<int>());

Your code as is doesn't actually use the result so it's hard to make a suggestion

Caius Jard
  • 72,509
  • 5
  • 49
  • 80
  • result is being populated in the secont function and returned in the first. But this answers my question. thanks a lot! – Dev Feb 01 '22 at 16:49
  • No problem! If you click the grey check mark on the left to turn it green it will mark the question as answered which changes its appearance on the dashboard to let people know you're not still looking for an answer – Caius Jard Feb 01 '22 at 22:56
-2

You can only cast the outermost List to an IList. For example, this code would work:

// cast the outermost List to an IList - this works
IList<List<int>> stuff = new List<List<int>>();

However, the generic type specified for the outermost list (T = List<int> in my example above) cannot be cast, even to an interface that it implements.

This code does not work:

// cast the inner List to an IList - this is not supported
List<IList<int>> things = new List<List<int>>();

Unless there is some reason you really need to return an IList, you can simply update your function definition to return a List instead of an IList.

public List<List<int>> ThreeSum(int[] nums)

If you are interested in why this isn't supported, my opinion follows. The implicit casting of the generic types is incredibly complex to implement and is not supported in C#. To cast the generic type, the generic type constraints would have to be revalidated, every variable in memory of the type would have to be cast - which is an intensive operation fraught with opportunity for error - and it is quite possible that the casting into a new type would invalidate previous operations (e.g. through conditional pattern-matching logic) of the class containing the generic type.

John Glenn
  • 1,469
  • 8
  • 13
  • 4
    No, that's not why it's not supported, it's not because the language designers couldn't be bothered. It's not supported because not every `List` is an `IList`, so if you *could* cast it, someone could attempt to insert a value into the outer list which *is* an `IList` but *not* a `List`. It's all to do with assignment compatibility – Charlieface Jan 30 '22 at 03:05
  • @Charlieface - Yes, every List is an IList because List implements IList, right? The cast I'm referring to is the implicit cast of the generic type. – John Glenn Jan 30 '22 at 04:00
  • 1
    I recommend reading about [covariance and contravariance in generics](https://learn.microsoft.com/en-us/dotnet/standard/generics/covariance-and-contravariance). The reason this isn't allowed is because `List` is invariant. – Johnathan Barclay Jan 30 '22 at 08:15
  • True, but a `List>` is not a `List>`, because if so then it may allow you to add a `IList` (which is not a `List`) to it, which is provably not true. You are trying to apply covariance to it, and it cannot be covariant, it must be invariant – Charlieface Jan 30 '22 at 11:39