【问题标题】:Implementing .Net interfaces (C#)实现 .Net 接口 (C#)
【发布时间】:2011-04-07 21:22:49
【问题描述】:

可能是一个简单的问题。

我有一个接口 (MyInterface),它定义了如下属性:

IList<IMenuItem> MenuCollection { get; }

以及实现 MyInterface 的类

public class MyClass : MyInterface
{
    public ObservableCollection<MenuItemBase> MenuCollection 
    {
       get
       {
           ...
       }
    }
    ....
}

根据我的阅读,ObservableCollection 继承自作为 IList 的 Collection,并且我有实现 IMenuItem 的 MenuItemBase 类 - 这不满足接口吗?

我想接口必须显式实现?

我也试过这个:

public class MyClass : MyInterface
{
    public IList<IMenuItem> MenuCollection MenuCollection 
    {
       get
       {
           if(_menuCollection == null)
              _menuCollection = new ObservableCollection<MenuItemBase>();
           return _menuCollection as IList<IMenuItem>;
       }
    }
    private ObservableCollection<MenuItemBase> _menuCollection;
}

似乎是一种解决方法 hack(我确实遇到了一些问题,说 MenuCollection 没有被实例化)来满足接口......有没有更好的方法来实现 IInterface1&lt;IInterface2&gt; 对象?

我需要这种抽象的原因是因为我正在构建一个 prism / unity 应用程序,并且希望尽可能地将菜单视图模型与显示菜单的功能区 ui 分离。

【问题讨论】:

  • 对我来说,你的“变通办法”感觉是正确的做法......
  • 你甚至必须将_menuCollection 转换为IList&lt;IMenuItem&gt; 吗?如果ObservableCollection&lt;MenuItemBase&gt; 满足IList&lt;IMenuItem&gt;,你应该可以直接退货...不是吗?
  • 此外,我同意@Stormenet 的观点,即这并不是真正的“黑客”。您已经声明了一个具有泛型返回类型的方法,因此它的实现需要一个泛型返回类型。这意味着方法的调用者不需要担心方法实现使用的具体内部类型。我觉得不错。
  • 顺便说一句,您的 as 将始终返回 null...
  • @djacobson - 我尝试直接返回它,但它会导致编译时错误,我唯一的猜测是它不喜欢为 IList 返回 ObservableCollection - 我必须检查确切的错误当我回到工作岗位时再次

标签: c# .net interface


【解决方案1】:

乔恩是正确的;这与通用方差无关。但是,他没有提到您想要的功能称为return type covariance

也就是说,如果 Animal 是 Giraffe 的基本类型,则返回 Animal 的接口方法或返回 Animal 的虚拟方法可以由返回 Giraffe 的方法实现/特化。由于每只长颈鹿都是动物,因此合同已履行。

C# 不支持返回类型协方差;就此而言,CLR 也没有。一些语言支持返回类型协方差;例如,我想到了 C++。 (C++/CLI 实现做了一些偷偷摸摸的技巧来解决 CLR 的限制。)实现的接口方法的返回类型、属性的类型等等,都必须完全匹配在 C# 中。

【讨论】:

  • 你提到的 C++/CLI 的这些技巧可能会让你读起来很有趣;)
  • @Jon:他们没那么狡猾。正是你所期望的。生成了一堆帮助方法,它们只是真正重载的代理。
【解决方案2】:

这与泛型差异无关

关于通用方差的答案有很多。这与示例无关。如果您尝试使用ArrayList(无泛型)实现定义为IList 的属性,您会发现仍然无法这样做。

正确答案

这种行为是因为如果您可以将MenuCollection 实现为实现IList&lt;T&gt; 的某种类型的属性(或从它派生,如果它未指定为接口),那么这是可能的:

public interface MyInterface
{
    IList<IMenuItem> MenuCollection { get; set }
}

public class MyClass : MyInterface
{
    // WARNING: Does not count as implementing the interface -- with good reason
    public ObservableCollection<MenuItemBase> MenuCollection { get; set; }
}

var myClass = new MyClass();
var classAsInterface = (MyInterface) myClass; // This is OK of course

classAsInterface.MenuCollection = new List<MenuItemBase>(); // OOPS!!

在最后一行中,您已将List&lt;MenuItemBase&gt;(就MyInterface 可以判断,因为MyInterface.MenuCollection 属于IList&lt;MenuItemBase&gt; 类型)分配给ObservableCollection&lt;MenuItemBase&gt; 类型的属性。

当然,这样做是不合法的,因为List&lt;MenuItemBase&gt; 显然不是源自ObservableCollection&lt;MenuItemBase&gt;。但是,如果您可以实现这样的接口,那将是可能的。

【讨论】:

  • -1 他没有在他的接口的MenuCollection 属性中定义一个setter,只有一个getter。
  • @Stormenet:很明显,但是语言的规则不能根据你是否定义setter而改变。
【解决方案3】:

List&lt;T&gt;IList&lt;T&gt; 不支持协方差

看到这个问题:Question about C# covariance

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-27
    • 2018-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-28
    • 2011-06-04
    相关资源
    最近更新 更多