【问题标题】:How to pass a subclass parameter when implementing an interface in C#?在 C# 中实现接口时如何传递子类参数?
【发布时间】:2010-11-11 01:41:03
【问题描述】:

作为 OOP 的新手,我正在尝试通过传递(需要的)子类参数来实现带有基本参数的接口方法。我有:


public interface IArticleDataAccess { int SaveArticle(NewsArticle thisArticle); }

public AnalysisDataAccess : IArticleDataAccess {
  public int SaveArticle(AnalysisArticle thisArticle) {
    // Specific save code that needs properties of AnalysisArticle not found in NewsArticle.
}
public class AnalysisArticle : NewsArticle {
  IArticleDataAccess dataAccess = new ArchivedArticleDataAccess();
  int Save() {
    return dataAccess.SaveArticle(this);
  }
}

错误是“ArchivedArticleDataAccess'没有实现接口成员'IArticleDataAccess.SaveArticle(NewsArticle)'”,因为参数类型不一样。

我犯了一个小错误还是错过了基本的 OOP 概念?有没有我可以使用的模式来做到这一点?铸造还是泛型?或者这是 C# 的限制(不支持逆变参数)?

【问题讨论】:

    标签: c# class interface parameters


    【解决方案1】:

    你不能在这里应用逆变,因为它会破坏合同。我可以通过接口将任何类型的NewsArticle 发送到 SaveArticle 类,然后你的AnalysisDataAccess 会拒绝...

    你应该做的是使用泛型,像这样:

    public interface IArticleDataAccess<T> where T : NewsArticle
    {
        int SaveArticle(T thisArticle);
    }
    
    public AnalysisDataAccess : IArticleDataAccess<AnalysisArticle> {
      public int SaveArticle(AnalysisArticle thisArticle) {
        // Specific save code that needs properties of AnalysisArticle not found in NewsArticle.
    }
    public class AnalysisArticle : NewsArticle {
      IArticleDataAccess<AnalysisArticle> dataAccess = new AnalysisArticleDataAccess();
      int Save() {
        return dataAccess.SaveArticle(this);
      }
    }
    

    【讨论】:

      【解决方案2】:

      你可以做这样的事情。显式实现接口,确保参数是正确的类型并调用处理您实际想要的类型的公共方法。只要确保您知道在传递的 NewArticle 不是 AnalysisArticle 的情况下您想要做什么。此外,请仔细考虑此设计,并确定您想要并且需要将 AnalysisDataAccess 用作 IArticleDataAccess。

      IArticleDataAccess int SaveArticle(NewsArticle article)
      {
          AnalysisArticle analysisArticle = article as AnalysisArticle;
          if (analysisArticle != null)
                  SaveArticle(analysisArticle);
          //else handle error or another routine
      }
      
      public int SaveArticle(AnalysisArticle thisArticle)
      {
           //freely user analysis article members
      }
      

      【讨论】:

        【解决方案3】:

        您收到编译时错误,因为 ArchivedArticleDataAccess 必须实现 IArticleDataAccess 并且其声明需要如下所示:

        public class ArchivedArticleDataAccess : IArticleDataAccess 
        {
            public int SaveArticle(NewsArticle thisArticle) 
            {
                // Save the article and return some integer
            }
        }
        

        而不是:

        public class ArchivedArticleDataAccess : IArticleDataAccess 
        {
            public int SaveArticle(AnalysisArticle thisArticle) 
            {
                // Save the article and return some integer
            }
        }
        

        【讨论】:

          【解决方案4】:

          您无法更改在接口上实现的方法的类型,您需要更改它,以便将参数转换为方法实现中的正确类型,如下所示:

          public AnalysisDataAccess : IArticleDataAccess {
            public int SaveArticle(NewsArticle thisArticle) {
              AnalysisArticle theArticle = thisArticle as AnalysisArticle;
              if (theArticle != null) {
              // Specific save code that needs properties of AnalysisArticle not found in 
          

          新闻文章。 } }

          这应该可行。

          【讨论】:

            【解决方案5】:

            泛型的使用看起来很优雅。但是在尝试实现它时,我实际上并没有使用:

            
            IArticleDataAccess<AnalysisArticle> dataAccess = new AnalysisArticleDataAccess();
            //But instead have a DataAccess property in NewsArticle.  Once defined as:
            IArticleDataAccess DataAccess { get; set; }
            //If I change to:
            IArticleDataAccess<NewsArticle> DataAccess { get; set; }
            // It can't be implicitly set to type IArticleDataAccess<AnalysisArticle>.
            

            我还需要对 NewsArticle 进行泛型吗?自引用泛型看起来很吓人,需要进行大量更改。最好让每个子类用正确的类型重新实现 DataAccess 属性?还是我错过了什么?

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2020-07-29
              • 1970-01-01
              • 1970-01-01
              • 2013-04-09
              • 2020-11-14
              • 1970-01-01
              • 2016-01-27
              • 1970-01-01
              相关资源
              最近更新 更多