如何解决泛型方法中类型推断的限制
本文关键字:类型 泛型方法 何解决 解决 | 更新日期: 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();
}
}
}
问题:
- 你知道如何使这段代码工作(考虑到代码示例中的重要注释)?
- 如果没有,那么你会建议我如何解决它?我想保持代码简单明了。
假设我正确阅读了您的问题,您希望推断某些类型参数,而不是其他类型参数。这意味着你需要已经处于某种上下文中,它具有可以推断的类型参数,所以你可以指定其他的。你可以这样做:
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);
}
}
对我来说这看起来更简单——但这并不意味着你不能用"流畅"的方式来写。