c# - 从方法签名中的父类推断泛型失败
问题描述
我正在使用一个库,其中包含(数百个模板生成的)没有泛型修饰符的类,每个类都使用泛型修饰符扩展相同的类(本质上是为了缩短符号)。例如
class DArr : NumberObject<double, MyArrayIndexer> { ... }
class IArr : NumberObject<int, MyArrayIndexer> { ... }
class DMat : NumberObject<double, MyMatrixIndexer> { ... }
class IMat : NumberObject<int, MyMatrixIndexer> { ... }
class BMat : NumberObject<bool, MyMatrixIndexer> { ... }
and so on
我现在想编写处理这些函数的函数,该函数需要它们的内部类型(例如,内部副本需要知道每个元素是 4 字节还是 8 字节,以及正在使用什么类型的索引器)。因此,我对我的功能进行了签名:
public SomeUnrelatedClass<T> Process<T,TVal,T0>(SomeUnrelatedClass<T> obj) where T : NumberObject<TVal,T0> {
//here some tstuff that requires T, TVal and T0
}
但不幸的是,我似乎无法以我需要的方式使用它,即
SomeUnrelatedClass<DArr> input = ...;
SomeUnrelatedClass<DArr> output = Process(input);
因为它无法从(为什么??)推导出 TVal 和 T0,尽管它是唯一确定的。我该如何补救?将其称为SomeUnrelatedClass<DArr> output = Process<DArr,double,MyArrayIndexer>(input);
不是一种选择,因为实际上这些泛型有很多而且它们的名称也更长(而且这个函数将在未来的代码中使用数千次,所以我宁愿现在写一个更多复杂的函数,它正确并保持语法简单)。理想情况下,我不会做一长串“if type == ...”,因为类型列表是模板生成的,并且随着类型的添加会随着时间的推移而变化(这意味着这个模板将依赖于另一个模板, ETC。)
我想到了一些愚蠢的技巧,比如制作语法Process<T,TVal,T0>(SomeUnrelatedClass<T> obj,SomeUnrelatedClass<NumberObject<TVal,T0>> sameObj)
和调用SomeUnrelatedClass<DArr> output = Process(input,input);
,但我觉得这只是一个非常糟糕的修复。有什么更“正确”的方法来做到这一点?
解决方案
我认为您在这里可能会很幸运,因为 C# 不会根据您指定的约束来推断类型。我认为这是规范的一部分,我可以挖掘出来。但无论如何你也许可以解决你的问题:) - 我设法让以下运行。
{
var input = new DArr(12.34);
var output = Visitor.Process(input);
Console.WriteLine($"Type [{output.Obj.GetType()}] with value {output.Obj.MyType}");
}
{
var input = new IArr(42);
var output = Visitor.Process(input);
Console.WriteLine($"Type [{output.Obj.GetType()}] with value {output.Obj.MyType}");
}
// Generated output:
//
// Type [DArr] with value 12,34
// Type [IArr] with value 42
因此,无论您定义了多少类型,Process方法都会使用并将输入映射到正确的具体类型。
以下是它的工作原理:
public class NumberObject<TType, TIndexer>
{
public NumberObject(TType type) { MyType = type; }
public TType MyType { get; }
}
public class MyArrayIndexer { }
public class DArr : NumberObject<double, MyArrayIndexer>
{
public DArr(double value) : base(value) { }
}
public class IArr : NumberObject<int, MyArrayIndexer>
{
public IArr(int value) : base(value) { }
}
public class SomeUnrelatedClass<T>
{
public T Obj { get; }
public SomeUnrelatedClass(T obj){ Obj = obj; }
}
public class Visitor
{
public static SomeUnrelatedClass<NumberObject<TVal, T0>> Process<TVal, T0>(NumberObject<TVal, T0> input)
{
return new SomeUnrelatedClass<NumberObject<TVal, T0>>(input);
}
}
这里的技巧是减少泛型参数的数量 - 摆脱T类型,因为它可以直接由其余两个表示,因为您实际上也自己编写
T is NumberObject<TVal, T0>
当要推断的类型级别降低时,C# 编译器可以直接确定它们,中提琴您可以让您为Process方法指定泛型参数。
推荐阅读
- php - 如何根据数据库中的列排序日期,最近的日期在顶部
- python - 如何将参数传递给 PyQt QThreadPool 运行函数
- python - 从字符串中提取二维列表
- blazor - Blazor 登录页面自定义
- c - 在数组中查找 NOT 整数的第一个实例
- angular - 角度嵌套表问题?
- javascript - 在特定条件下删除特定字符串部分的算法
- ios - 如何以编程方式将输入的登录(电子邮件)详细信息传递给另一个 ViewController?
- c++ - 它可能与 GL_LINE_LOOP(小行星)对象和点对象(子弹)发生碰撞?
- delphi - Delphi VCL表单箭头键管理解决方案触发两次