re: Universally quantified types in C# VIEW POST


Your problem is interesting. It feels like it should work, but it doesn't.
The question is really, why can't I convert IList<int> to IList<T>? Or IList<object> for that matter, since int is an object. Let's assume we could:

var ints = new List<int> { 1,2,3 };
var objs = (IList<object>)ints;

Only now I should be able to do objs.Add(new object()), and that clearly is not the case.

For your specific problem, you don't actually use the type of the list in any way, so you need to use a base type that is not generic, like System.Collections.IList:

        private static int SumWeights(
            IList<int> ints, 
            IList<string> strs, 
            Func<IList, int> getWeight) 
            => getWeight((IList)ints) + getWeight((IList)strs);

And I know your objection would be that you didn't mean specifically IList<T>, but anything, which might not have a non generic base class. Perhaps the feature in C# that you are looking for is something like this:

        private static int SumWeights(
            IList<int> ints, 
            IList<string> strs, 
            Func<IList<>, int> getWeight) 
            => getWeight(ints) + getWeight(strs);

But that's illegal in C#. A working solution could be using Func<object,Type,int> and then you would call it like getWeight(ints,typeof(IList<>)), which is legal, only now you have to do a lot of reflection in getWeight.


Thanks for your response. Can you make it work with a generic getWeight (i.e. one that takes an IList<T>) and without using reflection? It can be done!


Hmm... there are multiple ways to do it. I don't like any of them. This might work:

private static int SumWeights(
            IList<int> ints, 
            IList<string> strs, 
            Func<dynamic,int> getWeight) 
            => getWeight(ints) + getWeight(strs);
Console.WriteLine(SumWeights(ints, strs, x=>getWeight1(x)));

You’re on the right track with your idea to insert something that prevents the generic-ness of getWeight from bubbling up to SumWeights. However, it can be done safely, without going around the compiler’s type checker via dynamic.

You can't pass a generic function as a parameter without having your own function be generic. Therefore you need to encapsulate it. Like in an interface. This would be the best design for your problem.

    interface IWeighter
        int getWeight<T>(IList<T> list);

But you want to pass a function as a parameter, so probably this ain't it. I have the feeling that whatever you're proposing will not sit well with me.

You got it. That interface is exactly what I'd suggest. You're still passing in the function, just with one level of indirection. It's a bit more verbose, but not too bad, I think. Nice work!

code of conduct - report abuse