簡體   English   中英

聲明從接口方法返回的結構

[英]Declaring a struct to be returned from an interface method

我在C#(2.0)中編寫一個必須返回簡單對象集合的方法。 通常我會做這樣的事情:

class MyWidget
{
    struct LittleThing
    {
        int foo;
        DateTime bar;
    }

    public IList<LittleThing> LookupThings()
    {
        // etc.
    }
}

但是,我必須在接口中聲明此方法。 調用者無法看到MyWidget ,只能看到IWidget接口。 上述設置在這種情況下不起作用,因為C#不允許在接口內定義類型。 做這種聲明的正確或最佳方式是什么?

我想到的直接的事情是簡單地在界面之外聲明LittleThing 出於幾個原因,這看起來並不好。 一:它只用於那個單一類中的單一方法,所以LittleThing似乎不應該只是一個獨立的類型。 二:如果為其他類編寫類似的方法,它們將返回不同類型的數據(出於良好的設計原因),並且我不希望使用大量相似命名的結構來混淆名稱空間彼此。

如果我們可以升級我們的.Net版本,我只會返回一個Tuple<> ,但這還不會是一段時間的選擇。

[編輯添加:小對象確實需要包含兩個以上的字段,因此KeyValuePair<K,V>不會完全削減它。]

[編輯進一步補充: IWidget只由一個類Widget 我認為只有一個類的接口很奇怪,但這樣做是為了滿足舊的編碼策略,該策略要求契約始終與實現分開。 所述政策現已消失,但我們沒有資源重構整個應用程序並刪除所有不必要的接口。]

什么是最佳做法?

如果“LittleThing”只有兩個值,則可以返回KeyValuePair<TKey,TValue>

如果有兩個以上,你可以隨時創建自己的Tuple類,並在最終轉移到.NET 4時將其替換為.NET 4。

否則,我只想用接口定義結構,並將其作為API的一部分包含在內。 命名空間負責命名問題......

  1. 為什么要使用結構? 為什么不使用類呢?
  2. 單獨聲明該類,作為公共類。

您可以在interface外部聲明struct ,但在嵌套的namespace

如果我們可以升級我們的.Net版本,我只會返回一個元組<>,但這還不會是一段時間的選擇。

干嘛要等? 它不像元組是一件復雜的事情。 這是3元組的代碼。

public struct Tuple<TItem1, TItem2, TItem3>
{
    public Tuple(TItem1 item1, TItem2 item2, TItem3 item3)
    {
        this = new Tuple<TItem1, TItem2, TItem3>();
        Item1 = item1;
        Item2 = item2;
        Item3 = item3;
    }

    public static bool operator !=(Tuple<TItem1, TItem2, TItem3> left, Tuple<TItem1, TItem2, TItem3> right)
    { return left.Equals(right); }

    public static bool operator ==(Tuple<TItem1, TItem2, TItem3> left, Tuple<TItem1, TItem2, TItem3> right)
    { return !left.Equals(right); }

    public TItem1 Item1 { get; private set; }
    public TItem2 Item2 { get; private set; }
    public TItem3 Item3 { get; private set; }

    public override bool Equals(object obj)
    {
        if (obj is Tuple<TItem1, TItem2, TItem3>)
        {
            var other = (Tuple<TItem1, TItem2, TItem3>)obj;
            return Object.Equals(Item1, other.Item1)
                && Object.Equals(Item2, other.Item2)
                && Object.Equals(Item3, other.Item3);
        }
        return false;
    }

    public override int GetHashCode()
    {
        return ((this.Item1 != null) ? this.Item1.GetHashCode() : 0)
             ^ ((this.Item2 != null) ? this.Item2.GetHashCode() : 0)
             ^ ((this.Item3 != null) ? this.Item3.GetHashCode() : 0);
    }
}

如你所見,這沒什么大不了的。 我在當前項目中所做的是實現2,3和4元組,以及帶有Create方法的靜態Tuple類,它完全反映了.NET 4元組類型。 如果你真的是偏執狂,你可以使用反射器來查看.NET 4元組的反匯編源代碼,並逐字復制

當我們最終升級到.NET 4時,我們只會刪除這些類,或者#ifdef它們

在此處忽略結構名稱的含義,您可以使用KeyValuePair的通用版本。

接口只定義了可以在另一個類上實現的內容,這就是為什么你不能在它們內部給出任何定義的原因。 包括類和結構。

也就是說,通常用於解決此限制的一種模式是定義具有相同名稱的類(不包括“I”前綴)以提供任何相關定義,例如:

public interface IWidget
{
    IList<Widget.LittleThing> LookupThings();
}

// For definitions used by IWidget
public class Widget
{
    public struct LittleThing
    {
        int foo;
        DateTime bar;
    }
}

此模式的示例可以在BCL中找到,特別是使用泛型和擴展方法,但也可以使用默認值(例如EqualityComparer<T>.Default )甚至默認實現(例如IList<T>List<T> )。 以上只是另一種情況。

所以,閱讀你所評論的所有內容是我的想法:

  1. 如果實現IWidget的所有類型都返回LittleThing:

    然后我認為LittleThing的最佳實踐與IWidget處於相同的命名空間級別,最好是在Widgets命名空間。 但是你真的應該考慮讓LittleThing成為一個類。 通過你對問題的描述,似乎它可能不會那么少,因為每次實現IWidget的類都會使用某些字段而不是其他字段。

  2. 如果實現IWidget的所有類型都需要返回稍微不同的值,但具有類似的行為:

    考慮制作IThing界面。 然后每個IThing實現都完全依賴於返回它的類,那么你就可以在實現IWidget的類中聲明實現IThing的結構或類,如下所示:

     interface IWidget { IList<IThing> LookupThings() { … } } interface IThing { … } class MyWidget : IWidget { IList<IThing> IWidget.LookupThings() { … } private class MyWidgetThings : IThing { … } } 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM