2011-11-08 96 views
7

是否可以实现受限于两个唯一泛型参数的类?具有两个不相等(唯一)类型的泛型类

如果不是,那是因为它没有实现,或者因为语言结构(继承)而不可能?

我想形式的东西:

class BidirectionalMap<T1,T2> where T1 != T2 
{ 
    ... 
} 

我实施Bidirectional dictionary。这主要是好奇心问题,而不是需要。


意译从注释:

  1. 丹:“什么是负面后果,如果这种限制不符合”

  2. 我:“那么用户可以使用map [t1]和map [t2]来索引,如果它们是相同的类型,那么就没有区别,这是没有任何意义的。丹:编译器实际上允许[两个泛型类型参数定义不同的方法重载],所以我很好奇; 它是否随意挑选其中一个方法来调用?

+1

您可以在构造函数中始终抛出一个'ShouldBeBeCompileTimeError()' 。 :-) – foson

+1

可能是因为它没有意义,它们是泛型,不应该被类型“约束”。 – GriffinHeart

+0

出于好奇,如果不满足这个约束,会有什么负面影响?来自同一组的对象之间的映射是非常普遍的要求。 –

回答

4

扩大的例子突出问题:

public class BidirectionalMap<T1,T2> 
{ 
    public void Remove(T1 item) {} 
    public void Remove(T2 item) {} 

    public static void Test() 
    { 
     //This line compiles 
     var possiblyBad = new BidirectionalMap<string, string>(); 

     //This causes the compiler to fail with an ambiguous invocation 
     possiblyBad.Remove("Something"); 
    } 
} 

因此,答案是,即使你不能指定约束T1 = T2,也不要紧,因为编译器只要你试图做一些违反隐含约束的事情就会失败。它仍然在编译时捕获失败,所以你可以使用这些重载而不受惩罚。这有点奇怪,因为你可以创建一个地图实例(甚至可以编写IL代码来适当地操作地图),但C#编译器不会让你通过任意解决模糊的重载而造成破坏。


一方面要注意的是,如果你不小心,这种重载可能会导致一些奇怪的行为。如果你有一个BidirectionalMap<Animal, Cat>和猫:动物,可以考虑将与此代码发生的事情:

Animal animal = new Cat(); 
map.Remove(animal); 

这将调用了一个动物的过载,所以它会尝试删除键,即使你可能已经打算删除值Cat。这是一个有些人为的情况,但是当由于方法重载而出现非常不同的行为时,请谨慎行事。在这种情况下,如果您只是给方法不同的名称,反映它们的不同行为(比如RemoveKey和RemoveValue,假设),则读取和维护可能会更容易。

+0

优秀的根本答案!错误文本:'在以下方法或属性之间调用不明确:BidirectionalMap .this [T]'和'BidirectionalMap .this [K]'“ – user664939

0

类型约束似乎是不恰当的。虽然它们约束了类型参数,但目的是让编译器知道该类型可用的操作。
如果你想,你可以有一个约束,其中T1和T2都来自单独的具体基类,但我不认为这就是你想要的。

-1

没有任何有效的方法来做到这一点,而不会对类型本身施加任何其他限制。正如其他人指出的那样,您可以对这两种类型从两个不同的基类派生出来进行约束,但从设计的角度来看,这可能不是很好。

编辑补充说:这个没有实现的原因很可能是因为微软没有人考虑过这样的事情在编译时需要强制执行,与其他约束条件不同,这些约束条件与您的实际能力有什么关系使用指定类型的变量。正如一些评论者指出的那样,您可以在运行时强制执行此操作。

0

不等式不会帮助编译器捕获错误。当你指定对类型参数的约束时,你告诉编译器这种类型的变量将总是支持某个接口,或者将以某种方式运行。其中每一个都允许编译器验证更多的东西,比如“这个方法将会出现,所以它可以在T上调用”。

类型参数的不等式更像是验证方法参数不为null。它是程序逻辑的一部分,而不是其类型安全。

0

我不完全确定为什么这将是一个理想的编译时检查。基本上可以通过装箱键或值来绕过条件,从而使编译时检查无效。

需要考虑一些因素来确定......我试图防止哪些错误?

如果您只是停止不阅读文档的懒惰同事,然后添加一个仅调试检查并引发异常。通过这种方式,可以删除检查以获得释放代码。

#if Debug 

if (T1 is T2 || T2 is T1) 
{ 
    throw new ArguementException(...); 
} 

#endif 

如果你正试图阻止恶意的人利用以无意的方式库中,那么也许需要一个运行时检查,否则会很容易框中键或值。

+0

您也可以将此检查放在泛型类型的静态构造函数中,所以它只会运行一次(顺便说一下,你的检查不会被编译,因为'is'运算符的左边是一个对象引用,而不是一个类型名称,你需要if(typeof(T1)= = typeof(t2)') – phoog

0

不,你不能使用等式(或不等式)作为约束。简而言之,平等不是约束,而是一种条件。您应该测试条件,例如构造函数中类型的相等或不相等,并引发适当的异常。

相关问题