c#通用接口无法实现

时间:2014-08-13 12:39:28

标签: c# generics type-constraints

在我正在开发的库中,我需要多个不相关的类型来为(可能很多)“标签”提供值。每个标记都有一个相关的值类型,并表示为继承以下通用基础的(单例)类:

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

以上无法使用错误CS0455进行编译,因为类型TTag2继承了两个不相关的类约束Tag<TTag2,TValue2>Tag<TTag,TValue>(语言规则没有注意到这些“明显”的事实必须是平等的)。使该方法显式实现接口...崩溃编译器(mono 3.2.8)。

经过这么长时间的介绍,我的问题就出现了:是否有可能提出IProvider<TTag>的可实现定义而不牺牲任何(希望直觉上明确的)约束条件?如果没有,您能为原始方案建议不同的类型层次结构吗?谢谢!

P.S。让我排除任何将标记的值类型作为IProvider的泛型参数提及的实现 - 实际值类型足够复杂,因此无法推断它们会完全杀死使用库。

1 个答案:

答案 0 :(得分:0)

如果我看到这个结构快速浏览,那么在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界面上拥有{{1}}参数。