在我正在开发的库中,我需要多个不相关的类型来为(可能很多)“标签”提供值。每个标记都有一个关联的值类型,并表示为(单个)类,它继承了以下通用基数:
public abstract class Tag<TTag,TValue>
where TTag: Tag<TTag,TValue>
{
}
(类型参数
TTag
使用好奇重复模板模式)。我想提供一个接口
IProvider<TTag>
,它将标记可以为特定标签提供值的类。理想情况下,界面应如下所示:public interface IProvider<TTag>
{
TValue GetValue<TValue>(Tag<TTag,TValue> tag);
}
这将允许从提供的标签中推断出值的类型
(如果一个类型是多个标签的提供者)。
不幸的是,使用类
Tag<TTag,TValue>
要求他约束TTag: Tag<TTag,TValue>
,无法在此方法上指定,因为它的唯一通用参数是TValue
。我尝试这样做:public interface IProvider<TTag>
{
TValue GetValue<TTag2,TValue>(Tag<TTag2,TValue> tag)
where TTag2: Tag<TTag2,TValue>, TTag;
}
我的意图是,如果
TTag
是继承Tag<TTag,TValue>
的标记类,TTag2
满足这些约束的唯一方法是等于TTag
。用这种方式编写的接口可以正确编译。但是,实现会带来问题:
public struct Data<TTag,TValue> : IProvider<TTag>
where TTag: Tag<TTag,TValue>
{
public TValue Value;
public TValue2 GetValue<TTag2,TValue2>(Tag<TTag2,TValue2> tag)
where TTag2: Tag<TTag2,TValue2>, TTag
{
return (TValue2) Value;
}
}
由于类型
TTag2
继承了两个不相关的类约束Tag<TTag2,TValue2>
和Tag<TTag,TValue>
(语言规则没有注意到这些必须相等的“明显”事实),因此上述代码无法通过错误CS0455进行编译。使该方法显式实现接口...使编译器(单声道3.2.8)崩溃。经过漫长的介绍之后,我想到了一个问题:是否有可能提出一个可行的
IProvider<TTag>
定义,而又不牺牲任何(现在希望直观上很清楚的)约束?如果不是,您可以为原始方案建议不同的类型层次结构吗?谢谢!附言让我排除所有提及将标记的值类型作为
IProvider
的通用参数的实现-实际值类型足够复杂,因此无法推断它们完全无法使用该库。 最佳答案
就我所知,此结构在哪里发生了变化,在Data
结构中,您说的是TValue Value
方法中的字段TValue2
作为GetValue
返回。它不是同一类型。
因此,我要做的唯一一件事就是做到这一点:
public abstract class Tag<TTag, TValue>
where TTag: Tag<TTag,TValue>
{
}
public interface IProvider<TTag, TValue>
where TTag: Tag<TTag,TValue>
{
TValue GetValue(TTag tag);
}
public struct Data<TTag, TValue> : IProvider<TTag, TValue>
where TTag: Tag<TTag, TValue>
{
public TValue Value;
public TValue GetValue(TTag tag)
{
return Value;
}
}
但这与您在问题中的要求相冲突。
这使您更加接近:
public interface IProvider<TTag>
{
TValue GetValue<T, TValue>(T tag) where T : Tag<T, TValue>;
}
public struct Data<TTag, TValue> : IProvider<TTag>
{
public TValue Value;
public TV GetValue<T, TV>(T tag) where T : Tag<T, TV>
{
return (TV)(object)Value;
}
}
但是这里的问题仍然是
return (TV)(object)Value;
行-您不能将TValue
的值转换为TV
,因为此代码的全部目的是使GetValue
方法的返回类型保持自由。但这是不可能的。您必须在
TValue
界面上具有IProvider
参数。