繁体   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