【问题标题】:Strange inheritance modification奇怪的继承修改
【发布时间】:2011-10-27 19:52:36
【问题描述】:

我是一名 .NET 开发人员,对 OOP 非常了解。 然而,最近我注意到一个有趣的事实。

System.Data.SqlClient.SqlCommand 源自 System.Data.Common.DbCommand。后者实现System.IDbCommandSystem.IDbCommand 公开属性Connection,它是IDbConnection 的一个实例。 在DbCommand 但是这个属性返回DbConnection 类型。最后SqlCommand 中的相同属性的类型为SqlConnection

我尝试执行相同的操作,但它给出了编译时错误。在上面的示例中这是如何实现的?如何重新创建相同的模式?

我的代码(未编译):

public interface IFoo { }
public interface IBar 
{
   IFoo TheFoo();
}

public abstract class AbsFoo : IFoo { }
public abstract class AbsBar : IBar 
{
    public abstract AbsFoo TheFoo();
}

public class ConcreteFoo : AbsFoo { }
public class ConcreteBar : AbsBar { }

【问题讨论】:

  • 您需要同时使用 Jason 的 Richard 的答案来完成 SqlCommand 所做的事情。两个答案都是整体的两个部分。

标签: c# .net oop inheritance abstraction


【解决方案1】:

Explicit interface implementation 是这里的游戏名称。试试这个:

public abstract class AbsBar : IBar {
    IFoo IFoo.TheFoo() { return this.TheFoo(); }
    public abstract AbsFoo TheFoo();
}

这是implicit vs. explicit implementation 的一个很好的指南。

【讨论】:

  • 我将IBar.TheFoo() 标记为抽象,第二个方法标记为公共抽象,但它仍然给我一个编译器错误
  • 对不起,我认为有必要实现显式声明的方法。我不能把它抽象化。
  • 这是不正确的,甚至无法编译。隐式与显式实现并不能解决问题。
  • @Jason 什么使用指令?您的代码无法编译。 SqlCommand 可以让 Connection 返回与 DbCommand 不同的类型的原因是因为 Connection 只是一个公共属性。您的编译错误是“修饰符 'abstract' 对此项目无效”。文档有误,查看对象浏览器,您会看到 DbCommand.Connection 的签名是 public DbConnection Connection { get;放; },SqlCommand.Connection 的签名是 public SqlConnection Connection { get;放; }。我正在看它。
  • 此外,如果您在对象浏览器中查看 SqlCommand,并打开 show Inherited Members,您将看到两个 Connection 属性,一个返回 DbConnection,另一个返回 SqlConnection,但返回 DbConnection 的那个隐藏正常访问。
【解决方案2】:

我不得不说,我认为 Richard 做得有点困难 - 他的回答和 Jason 的回答一样好,因为他们都只回答了一半这个问题。 把它们放在一起,你就有了完整的答案。

要使用IDbCommandDbCommandSqlCommand,必须在DbCommand 中显式实现IDbCommandJason 的回答)和公共方法阴影SqlCommand理查德的回答)。

我将给出完整的“Foo/Bar”示例。

从这些接口开始:

public interface IFoo
{
    IBar GetBar();
}

public interface IBar { }

接下来Foo 必须提供IFoo 的显式实现,以便从它自己的GetBar 方法返回Bar,而不是IBar

public abstract class Foo : IFoo
{
    IBar IFoo.GetBar()
    {
        return this.GetBar();
    }

    public Bar GetBar()
    {
        return this.GetBarInner();
    }

    protected abstract Bar GetBarInner();
}

public abstract class Bar : IBar { }

最后,SomeFoo 类必须隐藏 GetBar 才能返回 SomeFoo 实例:

public class SomeFoo : Foo
{
    public new SomeBar GetBar()
    {
        return new SomeBar();
    }

    protected override Bar GetBarInner()
    {
        return this.GetBar();
    }
}

public class SomeBar : Bar { }

我认为 Richard 的唯一信息是我将 new 关键字添加到阴影方法中,您可以摆脱编译器错误。

【讨论】:

  • 第 3 方观察万岁。 :)
【解决方案3】:

DbCommand 和 SqlCommand 中的连接都是公共方法。会有编译器警告,但这是允许的。你的代码应该更像这样才能像 SqlCommand/DbCommand 一样工作:

    public interface IFoo { }
public abstract class AbsBaseBar
{
    public IFoo TheFoo() { throw new NotImplementedException(); }
}
public class AbsFoo : IFoo { }
public class AbsBar : AbsBaseBar
{
    public AbsFoo TheFoo() { throw new NotImplementedException(); }
}

public class ConcreteFoo : AbsFoo { }
public class ConcreteBar : AbsBar { } 

【讨论】:

  • 我认为你在这里做得有点难,Richard - 你确实非常正确地回答了问题的 一半。杰森完全错过了你的一半。我给了你一个赞成票来摆脱负面影响。
猜你喜欢
  • 2012-08-20
  • 2014-06-30
  • 1970-01-01
  • 2011-03-13
  • 2012-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-31
相关资源
最近更新 更多