C#Type Union with Interfaces

时间:2010-07-05 22:59:15

标签: c# graph

所以我非常喜欢数据结构,我一直在研究一个以不同方式实现不同类型图形的类库。我遇到的绊脚石之一就是试图轻松组合不同类型图表的特定功能。

为了澄清,假设我有一个名为IGraph< T>的接口,其中T是每个节点保存的数据。现在,我还希望拥有IUndirectedGraph< T>,IDigraph< T>和IWeightedGraph< T,E>的接口,其中E是用作权重的类型。

我希望能够提供相同类型图表的不同实现。例如,我希望能够提供一个使用邻接列表的类和一个使用邻接矩阵的类。这些类可能具有稍微不同的某些算法的实现。举个简单的例子,确定给定对象的邻居在每个实现中都是不同的。

所以,假设我有这两个类声明:

class WeightedAdjacencyListGraph<T,E> : IUndirectedGraph<T>, IWeightedGraph<T,E>

class WeightedAdjacencyMatrixGraph<T,E> : IUndirectedGraph<T>, IWeightedGraph<T,E>

我希望能够声明一个可以存储这两个类的对象的变量类型,同时保持所有接口中定义的功能。基本上,我希望能够声明一个变量类型,如:

<IUndirectedGraph<object>+IWeightedGraph<object,double>> MyGraph = new WeightedAdjacencyListGraph<object,double>();
MyGraph = new WeightedAdjacencyMatrixGraph<object,double>();

显然,变量类型声明不是正确的C#语法,但是我会把它放在这里?我是否必须为每个接口组合创建一个新接口?我的设计是否存在根本缺陷,如果是这样,我应该怎么做才能纠正它?

编辑:我决定为有向/无向图创建不同的名称空间,并在根名称空间中存储公共接口(例如IWeightedGraph&lt; T,E&gt;)。然后,我将基本上创建上面提到的组合接口(在答案中也会注明)。我认为有针对性/无向图不太可能在有趣的算法方面共享很多共同点。

4 个答案:

答案 0 :(得分:4)

如果你想规定两个合同都已完成以便在某种情况下使用某种类型,那么声明一个需要两者的新接口,并实现:

public interface IUndirectedAndWeightedGraph<T,E> :
    IUndirectedGraph<T>, IWeightedGraph<T,E>
{
}

任何实现此功能的类也会履行单个合同,因此您仍然可以将任何实现IUndirectedAndWeighted的类视为IUndirected等等。

你的理论方法在c#,单继承多态的背景下存在根本缺陷。该模型要求您将变量定义为特定的单个“形状”,并且只有明确(非隐式)适合该形状的对象才能放置在该变量中。使用dynamic可以允许某些类似的组合,但这有其自身的权衡 - 即,您失去了强类型和接口的好处。

答案 1 :(得分:2)

您可以使用泛型和类型约束在有限的方法参数中执行此操作:

void ProcessGraph<TGraph>(TGraph graph)
    where TGraph: IUndirectedGraph<T>, IWeightedGraph<T,E>
{
}

问题在于doesn't play nice方法重载。

但更一般地说,返回类型或变量没有类似的东西。正如其他答案所述,您必须明确定义“联合接口”,并确保所有可以实现它的类都这样做。如果所讨论的所有接口都是你的,如果你没有很多接口,这是一种可行的(如果单调乏味的)方法。

答案 2 :(得分:1)

我认为你可以创建一个接口,它是你想拥有的接口的组合。所以在你的例子中:

IComboGraph<T, E> : IUndirectedGraph<T>, IWeightedGraph<T,E>

class WeightedAdjacencyListGraph<T,E> : IComboGraph<T, E>

class WeightedAdjacencyMatrixGraph<T,E> : IComboGraph<T, E>

然后使用它:

IComboGraph<object, double> MyGraph = new WeightedAdjacencyListGraph<object,double>();
MyGraph = new WeightedAdjacencyMatrixGraph<object,double>();

编辑:我应该补充一点,你的combo界面不必包含任何内容,但可以定义为从这些界面继承。

答案 3 :(得分:0)

您的设计对我来说似乎很合理,但遗憾的是没有明智的方法来满足您的需求。

  1. 为所有组合创建接口是一种可能的解决方案,但如果您有三个,四个或更多接口,那么这也是一场噩梦。

  2. 在C#4.0中,您可以使用dynamic。这需要一些强大的静态类型和可能的性能 - 我也会尽量避免这种情况。

  3. 在可能的情况下,您可以使用具体类型或var来更轻松地进行更改,但代价是更紧密的耦合。

  4. 您还可以编写一个实现所有接口的包装器,并自己将调用分派给包装实例 - 也很讨厌。