【问题标题】:Generic interface parameters in a generic interface泛型接口中的泛型接口参数
【发布时间】:2014-08-24 10:21:05
【问题描述】:

我有以下通用接口:

public interface IContainer<T>

以及充当这些通用接口容器的通用接口:

public interface IGroupOfContainers<TContainer, TValue>
    where TContainer : IContainer<TValue>

现在我可以定义一些类了:

public class SomeContainer<T> : IContainer<T>
...

public class OtherContainer<T> : IContainer<T>
...

public class SomeGroupOfContainers<TContainer, TValue>
    : IGroupOfContainers<TContainer, TValue>
    where TContainer : IContainer<TValue>
...

public class OtherGroupOfContainers<TContainer, TValue>
    : IGroupOfContainers<TContainer, TValue>
    where TContainer : IContainer<TValue>
...

现在我希望IntGroupManager 能够处理任何符合IGroupOfContainers&lt;IContainer&lt;int&gt;, int&gt; 接口的对象:

public class IntGroupManager
{
    public IGroupOfContainers<IContainer<int>, int> IntGroup { get; set; }
    ...
}

但是当我尝试时:

var manager= new IntGroupManager();
manager.IntGroup = new GroupOfContainers<Container<int>, int>
    as IGroupOfContainers<IContainer<int>, int>;

我收到 “可疑演员表:没有从 GroupOfContainers&lt;Container&lt;int&gt;, int&gt;IGroupOfContainers&lt;IContainer&lt;int&gt;, int&gt; 继承的类型”警告,当我尝试运行代码时,manager.IntGroup 已设置到null,因为演员表失败了。

如果我将IntGroup 属性的类型签名更改为

public IGroupOfContainers<Container<int>, int> IntGroup { get; set; }

(将IContainer更改为具体类Container),代码可以正常执行。但是,我将无法使用IntGroup 类型(例如GroupOfContainers&lt;OtherContainer&lt;int&gt;, int&gt;)实例化IntGroupManager 的实例,因为OtherContainer 不是从Container 派生的。

我可以在IntGroupManager的定义中引入泛型参数,或许可以重写为

public class IntGroupManager<TContainer> where TContainer : IContainer<int>

但是,这会将IntGroupManager 的任何实例绑定到IContainer 的特定类型;我做不到

var manager = new IntGroupManager<Container<int>>();

// Set manager.IntGroup and do some things with it
// This is okay
manager.IntGroup = new GroupOfContainers<Container<int>, int>();
// manager executes some code involving IntGroup and manipulates its internal state

// Set manager.IntGroup to something else and do things with it
// This is not okay, since OtherContainer<int> is not derived from Container<int>
manager.IntGroup = new GroupOfContainers<OtherContainer<int>, int>();

所以我失去了一些灵活性。

如何正确地将IntGroup 属性定义为符合IGroupOfContainers&lt;IContainer&lt;int&gt;, int&gt; 的任何类型?我希望能够将IntGroupManager 的同一个实例与任何符合IGroupOfContainers&lt;IContainer&lt;int&gt;, int&gt;IntGroup 对象一起使用。有没有办法做到这一点?

【问题讨论】:

    标签: c# .net generics interface


    【解决方案1】:

    这是在 Mehmet 的回答的 cmets 中对您的问题的回答(抱歉,评论太长了):

    如果它是输入或输出,而不是两者,[协方差] 将是解决方案,对吗?即使 IGroupOfContainers 定义了使用 TContainer 作为输入和输出的函数,还有什么方法可以做到这一点?

    让我们继续您的示例并假设以下语句有效:

    var g = new GroupOfContainers<Container<int>, int>
        as IGroupOfContainers<IContainer<int>, int>;
    

    假设IGroupOfContainers&lt;TContainer, TValue&gt;有一个方法AddContainer(TContainer)

    g.AddContainer(new OtherContainer<int>());
    

    这会编译,因为OtherContainer&lt;int&gt;IContainer&lt;int&gt;

    但是,您刚刚将OtherContainer 添加到Containers 组中!这就是为什么你不能做你想做的事,除非你阻止 IGroupOfContainers 接受 TContainer 输入。

    【讨论】:

    • 这很清楚为什么 C# 会有这样的行为。感谢您的澄清!
    【解决方案2】:

    虽然很难说没有看到您如何使用TContainerTValue(输入或输出?)但是,您是否尝试过使用out 关键字作为泛型类型参数?详情可以查看Covariance and Contravariance

    public interface IContainer<out T>
    
    public interface IGroupOfContainers<out TContainer, TValue>
        where TContainer : IContainer<TValue>
    

    【讨论】:

    • 如果它是输入或输出,而不是两者,这将是解决方案,对吧?即使 IGroupOfContainers 定义了使用 TContainer 作为输入和输出的函数,还有什么方法可以做到这一点?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-08-23
    • 2018-09-15
    • 2018-07-23
    • 1970-01-01
    • 2020-09-16
    • 2011-03-14
    • 2012-03-01
    相关资源
    最近更新 更多