【问题标题】:Generic container interface parameterized by specific generic contained interface由特定泛型包含接口参数化的泛型容器接口
【发布时间】:2014-08-23 18:13:42
【问题描述】:

目标:

创建由实现另一个特定通用接口的类型参数化的通用接口。

问题:

我正在尝试用 C# 编写以下相关接口,但我无法确定我正在尝试做的事情是否可行。

public interface IVersion<T>
{
    IVersionManager<IVersion<T>> Parent { get; }
    // various other methods
}

public interface IVersionManager<T> where T : IVersion<T>
{
    IReadOnlyList<T> Versions { get; }
    T Current { get; }
    void AddVersion(T version);
    // various other methods
}

不幸的是,Visual Studio 似乎发现 IVersion&lt;T&gt; 界面中的自引用 (IVersionManager&lt;IVersion&lt;T&gt;&gt;) 相当令人反感。

它会抛出以下错误:

类型“IVersion&lt;T&gt;”必须可转换为“IVersion&lt;IVersion&lt;T&gt;&gt;” 为了将其用作通用接口中的参数“T” 'IVersionManager&lt;T&gt;'

这听起来好像是圆形的,但我不认为它实际上是。

这对我来说很有意义。我疯了吗?这可能吗?我只是希望子版本能够引用它的父管理器。

Google 搜索没有找到任何东西。我怀疑也许我只是不知道如何表达这个问题。

【问题讨论】:

  • 感谢您建议使用不同的变量名。我在任何地方都使用 T 隐藏了我在 IVersionManager 中确实有循环引用的事实。嗯....
  • T 在你的IVersion 界面中应该代表什么?它应该是经理,不同的版本,还是别的什么?
  • 坦率地说,这并不重要。说它是字符串或整数。
  • 你要避免在你的课程中设计这样的循环——它们很快就会咬你。
  • 好的,这有帮助,所以关于在IVersion 接口上约束T 的答案不适用。

标签: c# generics interface containers restriction


【解决方案1】:

我想应该是这样的:

public interface IVersion<T>
{
    IVersionManager<T> Parent { get; }
    // various other methods
}

public interface IVersionManager<T>
{
    IReadOnlyList<IVersion<T>> Versions { get; }
    IVersion<T> Current { get; }
    void AddVersion(IVersion<T> version);
    // various other methods
}

无需定义where 约束即可实现类型安全。但缺点是您的VersionManagers 不是由实际的Version&lt;T&gt; 类型定义的,而是由用于定义Version&lt;T&gt;T 类型定义的。


我不知道有什么真正的方法可以同时实现定义IVersion's 泛型参数的能力以及仅使用一个泛型参数在IVersion 上使IVersionManager 泛型。

因此,要在 IVersion 实现者上实现真正的“通用性”,您必须使用更复杂的类型和限制:

public interface IVersion<T>
{
    IVersionManager<T> Parent { get; }
    // various other methods
}

public interface IVersionManager<TVersion, T> 
    where TVersion : IVersion<T>
{
    IReadOnlyList<TVersion> Versions { get; }
    TVersion Current { get; }
    void AddVersion(TVersion version);
    // various other methods
}

这有点多余和笨拙,但允许创建更多指定的VersionManagers,这在IVersion 实现者上是真正通用的。

【讨论】:

  • 嗯,是的,这样做的缺点是它不再定义版本类型......
  • 确实如此。我得考虑一下。我现在可以看出我很傻。
  • 指定它两次有点傻,但它完成了工作,并确保使用 IVersion 实现类型。感谢您的回答。
【解决方案2】:

如果您想避免在 IVersion 上放置约束,您可以在 IVersionManager 上展开约束。但是,这有点笨拙,因为您必须两次传递 T2 的类型

public interface IVersion<T>
{
    IVersionManager<IVersion<T>, T> Parent { get; }
}

public interface IVersionManager<T, T2> where T : IVersion<T2>
{
    IReadOnlyList<T2> Versions { get; }
    T2 Current { get; }
    void AddVersion(T2 version);
    // various other methods
}

【讨论】:

    【解决方案3】:

    你可以通过将限制添加到Version&lt;T&gt;编译

    // Define other methods and classes here
    public interface IVersion<T> where T:IVersion<T>   // <----- add restriction here
    {
        IVersionManager<T> Parent { get; }  // <--- change generic type here
        // various other methods
    }
    
    public interface IVersionManager<T> where T : IVersion<T>
    {
        IReadOnlyList<T> Versions { get; }  
        T Current { get; }
        void AddVersion(T version);
        // various other methods
    }
    

    是否正确正确由你来决定...

    【讨论】:

      【解决方案4】:

      您需要在IVersion 中为T 添加约束:

      public interface IVersion<T> where T : IVersion<T>
      {
          IVersionManager<T> Parent { get; }
          // various other methods
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-06-11
        • 2018-05-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-25
        • 2018-09-15
        相关资源
        最近更新 更多