c#通用接口无法实现

本文关键字:实现 接口 | 更新日期: 2023-09-27 18:18:01

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

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>的定义,而不牺牲任何(希望直观清楚现在)的约束?如果没有,您是否可以为原始场景建议一个不同的类型层次结构?谢谢!

注:让我排除任何将标记的值类型作为IProvider的泛型参数的实现——实际的值类型已经足够复杂,因此无法推断它们完全破坏了库的使用。

c#通用接口无法实现

这个结构倒下的地方,据我所见,是在Data结构中,你说字段TValue ValueGetValue方法中被返回为TValue2。这不是同一个类型。

所以我唯一能想到的就是这样做:

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方法的返回类型自由。但这是不可能的。

必须在IProvider接口上有TValue参数