如何解决泛型方法中类型推断的限制

本文关键字:类型 泛型方法 何解决 解决 | 更新日期: 2023-09-27 18:06:10

我试图实现通用方法,旨在将Tuple<Descendant>类型的对象转换为Tuple<Ancestor>类型的对象。我遇到了一个问题,似乎是c#语言的限制。

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();
        }
    }
}

问题:

  1. 你知道如何使这段代码工作(考虑到代码示例中的重要注释)?
  2. 如果没有,那么你会建议我如何解决它?我想保持代码简单明了。

如何解决泛型方法中类型推断的限制

假设我正确阅读了您的问题,您希望推断某些类型参数,而不是其他类型参数。这意味着你需要已经处于某种上下文中,它具有可以推断的类型参数,所以你可以指定其他的。你可以这样做:

using System;
public interface Interface { }
public class Class : Interface { }

public sealed class TupleHelper<T1>
{
    private readonly Tuple<T1> tuple;
    internal TupleHelper(Tuple<T1> tuple)
    {
        this.tuple = tuple;
    }
    // Unfortunately you can't express the constraint the way 
    // round you want here...
    public Tuple<TSuper1> Super<TSuper1>()
    {
        return new Tuple<TSuper1>((TSuper1) (object) tuple.Item1);
    }
}
public static class TupleExtensions
{
    public static TupleHelper<T1> To<T1>(this Tuple<T1> tuple)
    {
        return new TupleHelper<T1>(tuple);
    }
}
class Test
{
    static void Main()
    {
        Tuple<Class> tupleWithClass = new Tuple<Class>(new Class());
        Tuple<Interface> tupleWithInterfaceIncorrect = 
            tupleWithClass.To().Super<Interface>();
    }
}

…但这并没有给你想要的约束,因为你不能写where T1 : TSuper1

另一方面,您可以反转操作,像这样:
using System;
using System.Net;
public interface Interface { }
public class Class : Interface { }
public static class TupleHelper<T1>
{
    public static Tuple<T1> From<TDerived1>(Tuple<TDerived1> tuple)
        where TDerived1 : T1
    {
        return new Tuple<T1>(tuple.Item1);
    }
}
class Test
{
    static void Main()
    {
        Tuple<Class> tupleWithClass = new Tuple<Class>(new Class());
        Tuple<Interface> tupleWithInterfaceIncorrect = 
            TupleHelper<Interface>.From(tupleWithClass);
    }
}

对我来说这看起来更简单——但这并不意味着你不能用"流畅"的方式来写。