Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么不';t类型约束是方法签名的一部分吗?_C#_Generics_Overload Resolution_Type Constraints_Nested Generics - Fatal编程技术网

C# 为什么不';t类型约束是方法签名的一部分吗?

C# 为什么不';t类型约束是方法签名的一部分吗?,c#,generics,overload-resolution,type-constraints,nested-generics,C#,Generics,Overload Resolution,Type Constraints,Nested Generics,更新:从C#7.3开始,这应该不再是一个问题。从发行说明中: 当方法组包含某些类型参数不满足其约束的泛型方法时,这些成员将从候选集中删除 C#7.3之前的版本: 所以我读了,现在我了解到规范指定在重载解析后检查类型约束,但我仍然不清楚为什么会这样。下面是Eric的例子: static void Foo<T>(T t) where T : Reptile { } static void Foo(Animal animal) { } static void Main() {

更新:从C#7.3开始,这应该不再是一个问题。从发行说明中:

当方法组包含某些类型参数不满足其约束的泛型方法时,这些成员将从候选集中删除

C#7.3之前的版本:

所以我读了,现在我了解到规范指定在重载解析后检查类型约束,但我仍然不清楚为什么会这样。下面是Eric的例子:

static void Foo<T>(T t) where T : Reptile { }
static void Foo(Animal animal) { }
static void Main() 
{ 
    Foo(new Giraffe()); 
}
转换为:

static void Foo(Reptile  t) { }
为什么不能将类型约束“拉入”到形式参数列表中?这会以任何不好的方式改变签名吗?我觉得这只是加强了签名。然后,
Foo
将永远不会被视为重载候选对象


编辑2:难怪我的问题如此令人困惑。我没有正确阅读Eric的博客,引用了错误的例子。我在我认为更合适的示例中进行了编辑。我还把标题改得更具体一些。这个问题似乎不像我最初想象的那么简单,也许我遗漏了一些重要的概念。我不太确定这是stackoverflow材料,最好将此问题/讨论转移到其他地方。

如果
T
匹配多个约束,则会产生无法自动解决的歧义。例如,您有一个带有约束的泛型类

其中T:IFirst

还有一个是有约束的

其中T:ISecond

现在,您希望T成为一个同时实现
IFirst
ISecond
的类

具体代码示例:

public interface IFirst
{
    void F();
}

public interface ISecond
{
    void S();
}

// Should the compiler pick this "overload"?
public class My<T> where T : IFirst
{
}

// Or this one?
public class My<T> where T : ISecond
{
}

public class Foo : IFirst, ISecond
{
    public void Bar()
    {
        My<Foo> myFoo = new My<Foo>();
    }

    public void F() { }
    public void S() { }
}
公共接口IFirst
{
无效F();
}
公共接口等秒
{
无效S();
}
//编译器应该选择这个“重载”吗?
公共类我的哪里T:i第一个
{
}
//还是这个?
公共类My,其中T:ISecond
{
}
公共类Foo:i第一,i第二
{
公共空白栏()
{
My myFoo=新的My();
}
public void F(){}
public void S(){}
}
 > p>编译器不能将类型约束视为方法签名的一部分,因为它们不是CLR的方法签名的一部分。如果重载解析对不同的语言起着不同的作用,那将是灾难性的(主要是因为动态绑定可能发生在运行时,并且不同语言之间不应该有差异,否则所有的hells都会崩溃)


为什么决定这些约束不会成为CLR的方法签名的一部分是另一个问题,对此我只能做出不知情的假设。我会让知情者回答这个问题。

。这会导致名称冲突;在我的问题中,错误是由编译器不知道为方法调用选择哪个方法重载引起的:
Bar(new Iguana(),null)
。我可能有点慢,但我还没有看到这两者之间的联系。我将进一步研究您的示例。@EricJ您也可以在不使用泛型的情况下导致方法歧义-如果一个方法的两个重载分别为
IFirst
ISecond
,并且您尝试使用类型为
Foo
的参数解析要调用的方法,则会出现相同的情况。我不认为这就是C#团队决定不将其作为方法签名的一部分的原因。@ChrisShain-Hmm,但如果方法调用在IFirst和ISecond之间存在歧义,编译器将出错,您可以通过将参数强制转换到所需的接口来解决问题。如果泛型约束是方法签名的一部分,则需要在调用站点的不同约束之间选择语法,而对库的通用约束的任何更改都意味着调用代码必须重新编译才能继续工作,我认为这并不理想。您在问题顶部引用的关于鬣蜥的部分旨在说明一种情况,即类型推断确实考虑了约束,C中T的约束,因此重载解析最终选择了本例中的非泛型方法。你确定为了问这个问题,你想引用文章的相关部分吗?问题的其余部分似乎并没有从逻辑上遵循它。我认为您是想问,为什么当类型推断成功但推断出的类型违反了对方法类型参数的约束时,如果有替代方法,为什么重载解析会失败。我发现这个问题很让人困惑,但再一次,它是规范中一个让人困惑的部分。你是对的。我误读了你的博客,使用了错误的例子。难怪我的问题如此困惑。我尽可能地澄清我的问题;我还将阅读你的一些其他博客文章,看看是否可以提高我对这个主题的理解。我注意到Eric的博客文章有9页的评论(),Eric在其中写了大量的回复,回答了许多像我这样的问题。如果我有时间,我会把Eric的相关回答汇总起来。但这只是把问题从“为什么它不是C#的一部分转移到为什么它不是CLR的一部分”。。。支持考虑类型约束的重载解析有一个主要问题(请参见我的答案)。在一些.Net语言中有一些功能是其他语言无法实现的。主要给出的原因是辅助语法可以很容易地转换为正确的语法。这是非常简单的方法之一,只需确定要调用哪个方法。此外,这几乎不是语言中唯一可能出现歧义的情况,编译器完全没有理由不简单地使用它发现的内容,或者在无法解析特定方法调用时给出错误,就像它给出i
public interface IFirst
{
    void F();
}

public interface ISecond
{
    void S();
}

// Should the compiler pick this "overload"?
public class My<T> where T : IFirst
{
}

// Or this one?
public class My<T> where T : ISecond
{
}

public class Foo : IFirst, ISecond
{
    public void Bar()
    {
        My<Foo> myFoo = new My<Foo>();
    }

    public void F() { }
    public void S() { }
}