是否有可能在调用其中一种方法时编写在编译或运行时(即以任何方式)失败的内容?
<script>
$(document).ready(function(){
$("#filter button").click(function(){
var filtertag = $(this).attr('class');
$('.post:not(.'+filtertag+')').each(function(){ //gets all the non-filtered elements
if($(this).css('display') != 'none')
$(this).fadeOut(); //only fades out elements that are currently visible
});
$('.post').fadeIn(); //displays filter
}); //end of filter button click
}); //this is good practice
</script>
public static void Register<TInterface, TImplementation>()
where TImplementation : class, TInterface
{
}
以下内容将通过两个例子:
public static void RegisterRestrictive<TInterface, TImplementation>()
where TInterface : class
where TImplementation : class, TInterface
{
}
我不这么认为,因为你无法扩展结构?
而要求答案 0 :(得分:7)
问题是,据我所知:
class C<T, U> where T : class, U where U : class { }
class D<T, U> where T : class, U { }
D
是否存在C
合法的构造?
如果U
和T
关闭类型,则不会。也就是说,其中没有类型参数的类型。正如Jon Hanna的回答所指出的,开放式可能会导致问题:
class N<T, U> where T : class, U { C<T, U> c; D<T, U> d; }
D
的约束不符合,所以这种结构是非法的。
对于封闭类型的类型参数,我们可以推断如下:
在C
中,约束要求U
为引用类型。
在D
中,T
可以是类,接口,委托或数组。在每种情况下,U
必须与T
相同,或T
的基类,或T
的某些内容可转换为via(可能是变体)隐式引用转换。无论如何,U
都是引用类型。
请注意,C#编译器,CLR验证程序和JIT编译器都不需要推断出U
始终是引用类型!例如,在这种情况下,C#编译器会在U
的用法上生成不必要的装箱指令,即使您和我知道U
不会是正在构建的值类型。 / p>
这可能导致U
被装箱然后立即取消装箱的情况,以及我最后一次检查 - 这是,呃,十年前 - 抖动没有为该场景生成最佳代码。毫无疑问,自从我上次检查以来,抖动已被重写了一次或多次,你可能不应该接受我的说法。
这里的好习惯是将约束放在那里并拼出来。
一些有趣的相关事实:
你可以通过拉动像
这样的恶作剧来进入类似的情况class B<T> { public virtual void M<U>(U u) where U : T {} }
class D : B<int> { public override void M<U>(U u) { } }
请注意,C#不允许您重新声明约束,现在是where U : int
。但是,除了int之外,你不能用M
进行通用构造。
这可能导致IL生成中一些真正奇怪的场景,因为CLR有一个记录不完整的规则,因此它不允许类型参数的“已知为参考类型”的性能跨越虚拟覆盖进行更改。我为这些方法重新编写了codegen,试图获得一些可以编译,传递验证器,并且在放弃并返回C#2之前有效地几次次。
答案 1 :(得分:4)
是否有可能在调用其中一种方法时编写在编译或运行时(即以任何方式)失败的内容?
是的,这在编译时失败了:
public static void CallThem<TA, TB>()
where TB : class, TA
{
Register<TA, TB>(); // Fine
RegisterRestrictive<TA, TB>(); // CS0452
}
对于其中只有一个,没有一对匹配TInterface
和TImplementation
的具体类型,但调用方法的类型参数类型当然可以和类型参数类型相匹配是我们在设计API时需要考虑的类型以及具体类型。
约束不涉及其他约束的推断。