I’m trying to implement the generic method which is intended for converting objects of Tuple<Descendant> type to objects of Tuple<Ancestor> type. I’ve stuck with a problem which seems to be a limitation of the C# language.
using System;
namespace Samples
{
public static class TupleExtensions
{
public static Tuple<SuperOfT1> ToSuper<T1, SuperOfT1>(this Tuple<T1> target)
where T1 : SuperOfT1
{
return new Tuple<SuperOfT1>(target.Item1);
}
}
public interface Interface { }
public class Class : Interface { }
static class Program
{
static void Main()
{
var tupleWithClass = new Tuple<Class>(new Class());
// Next instruction lead the compilation to error. :( The compiler doesn't try to infer types if at least one of generic type arguments is explicitly declared.
var tupleWithInterfaceIncorrect = tupleWithClass.ToSuper<Interface>();
// Next instruction is correct. But it looks ugly.
var tupleWithInterfaceCorrect = tupleWithClass.ToSuper<Class, Interface>();
// The code I try to write in my software is even worse:
// I need to declare more types explicitly, because my actual tuple has more dimensions.
// var myTupleInProduction = tuple.ToSuper<Class1<T>, Class2<T>, Interface1<T>, Interface2<T>>();
// This code is VB.NET-like (too verbose). The problem is compounded by the fact that such code is used in many places.
// Can I rewrite my TupleExtensions to provide more laconic code like that:
// var myTupleInProduction = tuple.ToSuper<Interface1<T>, Interface2<T>>();
Console.ReadKey();
}
}
}
Questions:
- Do you have any idea how to make this code working (take in account important comment in the code sample)?
- If no, then how would you recommend me to work it around? I want to keep the code simple and clear.
Assuming I’ve read your question correctly, you want to infer some type parameters but not others. That means you’ll need to already be in some sort of context which has the type parameters that can be inferred, so you can specify the others. You can do it like this:
… but that doesn’t give you the constraint you want, because you can’t write
where T1 : TSuper1.On the other hand, you could invert the operation, like this:
This looks simpler to me – but it does mean you can’t write it in a “fluent” way.