在C#中實現接口時如何傳遞子類參數?

[英]How to pass a subclass parameter when implementing an interface in C#?


As a novice to OOP, I am trying to implement an interface method with a base parameter by passing a (needed) subclass parameter. I have:

作為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);
  }
}

The error is "ArchivedArticleDataAccess' does not implement interface member 'IArticleDataAccess.SaveArticle(NewsArticle)'" as the parameter types are not the same.

錯誤是“ArchivedArticleDataAccess”沒有實現接口成員'IArticleDataAccess.SaveArticle(NewsArticle)'“,因為參數類型不一樣。

Am I making a small mistake or missing a fundemental OOP concept? Is there a pattern I can use to do this? Casting or Generics? Or is this a limitation of C# (no contravariant parameter support)?

我犯了一個小錯誤或錯過了一個有趣的OOP概念嗎?有沒有我可以用來做這個的模式?鑄造還是仿制葯?或者這是C#的限制(沒有逆變參數支持)?

5 个解决方案

#1


You can't apply contravariance here since it would break contract. I could send any kind of NewsArticle to the SaveArticle class through the interface, and then your AnalysisDataAccess would barf...

你不能在這里申請逆轉,因為它會破壞合同。我可以通過界面將任何類型的NewsArticle發送到SaveArticle類,然后你的AnalysisDataAccess將barf ...

What you should do is use generics, like this:

你應該做的是使用泛型,如下所示:

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


You could do something like this. Explicitly implement the interface, make sure the argument is the proper type and call public method that handles the type you actually want. Just make sure you know what you want to do in case the NewArticle passed is not an AnalysisArticle. Additionally, think through this design and be certain you want and need to use AnalysisDataAccess as an IArticleDataAccess.

你可以這樣做。顯式實現接口,確保參數是正確的類型,並調用處理實際需要的類型的公共方法。如果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


You are getting a compile-time error because ArchivedArticleDataAccess must implement IArticleDataAccess and its declaration needs to look like this:

您收到編譯時錯誤,因為ArchivedArticleDataAccess必須實現IArticleDataAccess,其聲明需要如下所示:

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

and not:

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

#4


You can't change the type of a method you implement on an interface, you need to change it so you cast the parameter to the right type inside the method implementation like this:

您無法更改在接口上實現的方法的類型,您需要更改它,以便在方法實現中將參數強制轉換為正確的類型,如下所示:

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 

NewsArticle. } }

新聞文章。 }}

This should work.

這應該工作。

#5


The use of generics looks elegant. But in trying to implement it, I don't actually use:

仿制葯的使用看起來很優雅。但在嘗試實現它時,我實際上並沒有使用:


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>.

Do I need to also generic to NewsArticle<T>? The self-referencing generic looks scary and requires a lot of changes. Better to just have each subclass reimplement the DataAccess property with the right type? Or am I missing something?

我是否還需要通用於NewsArticle ?自引用泛型看起來很可怕,需要進行大量更改。最好讓每個子類重新實現具有正確類型的DataAccess屬性?或者我錯過了什么?


注意!

本站翻译的文章,版权归属于本站,未经许可禁止转摘,转摘请注明本文地址:https://www.itdaan.com/blog/2009/07/15/d0ca01264b0757f7a4bcdb27aa89e1c4.html



 
粤ICP备14056181号  © 2014-2021 ITdaan.com