【问题标题】:A question about interface inheritance in .NET关于.NET中接口继承的问题
【发布时间】:2011-06-12 21:35:15
【问题描述】:

我们以接口IQueryable<T>为例:

public interface IQueryable<T> : IQueryable, IEnumerable;

因为 IQueryable 又实现了 IEnumerable:

public interface IQueryable : IEnumerable;

为什么在第一个声明中,IQueryable 也必须显式实现 IEnumerable?这与不必显式从“祖父母”继承的类继承不同?

【问题讨论】:

  • “IQueryable 必须显式实现 IEnumerable”——来源? “明确实施”是什么意思?
  • @strager:在 MSDN 文档中,如果您查看 IQueryable 的声明,您会看到类似于我帖子中的第一个声明,其中 IQueryable 显式实现了两个 IQueryable还有IEnumerable,我觉得是多余的。
  • 它是因为像c#这样的语言支持接口继承,但IL不...所以编译器会在编译代码时直接为你显式实现所有接口。
  • 见泡利的解释和我的例子。您将看到文档和元数据是如何生成的。

标签: .net asp.net linq inheritance


【解决方案1】:

在声明中提及祖父母(和更高的祖先)不是绝对必要的,但是因为作为接口的父母实际上并没有实现祖父母,最好在孙子女的声明中提及祖父母为最终实施者改进文档

这就是为什么,在祖先的具体实现的情况下,您会在MSDN 中看到以下内容:

public class Button : ButtonBase,IButtonControl

而不是下面的……

public class Button : ButtonBase,Control,Component,MarshalByRefObject,Object

【讨论】:

    【解决方案2】:

    这不是真的。我怀疑您在 Visual Studio 中右键单击这些类/接口并单击“转到定义”,这就是 元数据 告诉您的内容。如果你想真正了解发生了什么,这里有一个例子:

        public interface IAddTwo
        {
            int AddTwo(int x);
        }
    
        public interface IAddTwoOrThree : IAddTwo
        {
            int AddThree(int y);
        }
    
        public class AddTwoOrThree : IAddTwoOrThree
        {
            public int AddTwo(int q)
            {
                return q + 2;
            }
    
            public int AddThree(int z)
            {
                return z + 3;
            }
        }
    

    请注意,最后一个类只需要实现一个接口(但如果您不使用任何一种方法,则会出现编译器错误。

    将上述创建为类库,通过 BROWSING 添加对生成的 DLL 的引用(而不是通过添加对项目的引用),并查看 AddTwoOrThree 的元数据。你会看到

    AddTwoOrThree : IAddTwoOrThree, IAddTwo
    

    维奥拉!这就是为什么您会看到您在 MSDN 上看到的内容。他们显示元数据,而不是他们的编码人员编写代码的方式。

    【讨论】:

    • 您好,如果您查看 MSDN 页面 msdn.microsoft.com/en-us/library/bb351562.aspx 上的语法部分,IQueryable 的声明类似于我帖子中的第一个声明。因此我有一个问题。
    • 没有。他们的帮助页面只是显示每个类/接口实现的元数据,但您不必在代码中以这种方式显式实现接口。如果您想了解发生了什么,请创建一个包含两个项目的 Visual Studio 解决方案。用我上面的代码创建一个类库。然后创建一个新项目并使用 BROWSE 添加对另一个 DLL 的引用(而不是通过添加项目引用)。现在实例化 AddTwoOrThree。当您右键单击并选择“转到定义”时,您可能会对所看到的内容感到惊讶。
    【解决方案3】:

    因为接口继承是纯粹的语言糖。编译到 IL 时,接口显式实现了链中的所有接口,因此查看 IQueryable&lt;T&gt; 的签名最终看起来像

    .class public interface abstract auto ansi IQueryable<+ T>
        implements [mscorlib]System.Collections.Generic.IEnumerable`1<!T>, System.Linq.IQueryable, [mscorlib]System.Collections.IEnumerable
    {
    }
    

    而且由于大多数文档是从元数据而不是原始源代码自动生成的,因此它最终会显示签名,因为它直接实现了所有接口,而不是通过继承。基本上就是这样。您可以利用继承的唯一原因是编译器最终会为您创建正确的签名,显式地连接所有接口。

    【讨论】:

      【解决方案4】:

      正确的定义是:

      public interface IQueryable<out T> : IEnumerable<T>, IQueryable { }
      

      以下内容取自 Microsoft 的 Source RTMRel\ndp\fx\src\Core\System\Linq\IQueryable.cs\1305376\IQueryable.cs

          public interface IQueryable : IEnumerable {
              Expression Expression { get; } 
              Type ElementType { get; } 
      
              // the provider that created this query 
              IQueryProvider Provider { get; }
          }
      
      #if SILVERLIGHT 
          public interface IQueryable<T> : IEnumerable<T>, IQueryable {
      #else 
          public interface IQueryable<out T> : IEnumerable<T>, IQueryable { 
      #endif
          } 
      
          public interface IQueryProvider{
              IQueryable CreateQuery(Expression expression);
              IQueryable<TElement> CreateQuery<TElement>(Expression expression); 
      
              object Execute(Expression expression); 
      
              TResult Execute<TResult>(Expression expression);
          } 
      
          public interface IOrderedQueryable : IQueryable {
          }
      
      #if SILVERLIGHT
          public interface IOrderedQueryable<T> : IQueryable<T>, IOrderedQueryable { 
      #else 
          public interface IOrderedQueryable<out T> : IQueryable<T>, IOrderedQueryable {
      #endif 
          }
      

      【讨论】:

      • 您好,如果您查看 MSDN 页面 msdn.microsoft.com/en-us/library/bb351562.aspx 上的语法部分,IQueryable 的声明类似于我帖子中的第一个声明。因此我有一个问题。
      • 不要在像 SO 这样的公共论坛上发布 .Net 的源代码。如果他们阅读过这样的资料,它会使人们无法为 ie Mono 做出贡献。 mono-project.com/Contributing 如果您查看过 Microsoft 的 .NET 专有实现或其共享源代码(也是专有的),您将无法为 Mono 做出贡献。如果您想在这方面做出贡献,请注意不要在 Visual Studio 调试体验中查看它们。
      • @Pauli Østerø:我没有发布源代码。我引用了来源,所以任何人都可以查看它。我确实发布了接口定义,可以从反射或对象浏览器中收集。
      • @Pauli Østerø:根据我的经验和我的解释,它们的意思是……在贡献时不要访问专有代码。您可以整天阅读代码。您甚至可以使用从阅读中获得的知识,但绝对不能使用实际的源代码作为参考,也不能使用任何其他工具来确定实现细节。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多