带接口的C#类型联盟

带接口的C#类型联盟

问题描述:

所以我非常喜欢数据结构,并且我一直在研究以不同方式实现不同类型图形的类库。我遇到的绊脚石之一是试图轻松地结合不同类型图形的特定功能。为了澄清,假设我有一个名为IGraph <T>的接口,其中T是每个节点所拥有的数据。现在,我还想要具有IUndirectedGraph <T>,IDigraT >和IWeightedGraph < T,E >的接口,其中E是用作权重的类型。带接口的C#类型联盟

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

所以,让我们说我有这两个类声明:

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 < T,E >)存储在根名称空间中。然后,我将基本创建上面提到的组合界面(这些也在答案中注明)。我认为无论如何,直接/无向图在共享有趣的算法时不可能共享很多共同点。

我想你可以创建一个接口,它是你想要的接口的组合。因此,在你的例子:

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>(); 

编辑:我要补充一点,你的二合一接口并不一定有它的任何东西,但被定义为那些继承接口。

如果要规定,这两项合同是为了在一定情况下使用一种类型的实现,然后声明既需要一个新的接口,并实施:

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

,将实现该任何类也履行个人合同,所以你仍然可以把任何实施了IUndirectedAndWeighted的课程当作IUndirected等。

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

您的设计对我来说似乎很合理,但不幸的是没有明智的方式来实现您的需求。

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

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

  3. 在可能的情况下,您可以使用具体类型或var以更紧密的耦合为代价来简化更改。

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

可以使用泛型为此在的方法参数的有限的情况下和输入约束:

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

美中不足的是,它与doesn't play nice方法重载。

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