C#方法重载解决方案未选择具体的通用替代 [英] C# Method overload resolution not selecting concrete generic override

查看:76
本文介绍了C#方法重载解决方案未选择具体的通用替代的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此完整的C#程序说明了此问题:

This complete C# program illustrates the issue:

public abstract class Executor<T>
{
    public abstract void Execute(T item);
}

class StringExecutor : Executor<string>
{
    public void Execute(object item)
    {
        // why does this method call back into itself instead of binding
        // to the more specific "string" overload.
        this.Execute((string)item);
    }

    public override void Execute(string item) { }
}

class Program
{
    static void Main(string[] args)
    {
        object item = "value";
        new StringExecutor()
            // stack overflow
            .Execute(item); 
    }
}

我遇到了StackOverlowException,我可以追溯到此我试图将呼叫转发到更具体的过载的呼叫模式。令我惊讶的是,调用不是选择更具体的重载,而是对其进行回调。显然,它与通用类型有关,但我不明白为什么它不选择Execute(string)重载。

I ran into a StackOverlowException that I traced back to this call pattern where I was trying to forward calls to a more specific overload. To my surprise, the invocation was not selecting the more specific overload however, but calling back into itself. It clearly has something to do with the base type being generic, but I don't understand why it wouldn't select the Execute(string) overload.

有人吗?

上面的代码被简化以显示该模式,实际结构稍微复杂一些,但是问题是相同的。

推荐答案

在C#规范5.0、7.5.3重载分辨率中提到了类似的内容:

Looks like this is mentioned in the C# specification 5.0, 7.5.3 Overload Resolution:


重载决议选择要在C#中以下不同上下文中调用的函数成员:

Overload resolution selects the function member to invoke in the following distinct contexts within C#:


  • 调用在invocation-expression(第7.6.5.1节)中命名的方法。

  • 调用在object-creation-expression(第7.6节)中命名的实例构造函数。 10.1)。

  • 通过元素访问调用索引器访问器(第7.6.6节)。

  • 调用预定义或用户定义的索引操作员参考

  • Invocation of a method named in an invocation-expression (§7.6.5.1).
  • Invocation of an instance constructor named in an object-creation-expression (§7.6.10.1).
  • Invocation of an indexer accessor through an element-access (§7.6.6).
  • Invocation of a predefined or user-defined operator referenced in an expression (§7.3.3 and §7.3.4).

这些上下文中的每一个都定义了候选函数成员$的集合。 b $ b和参数列表以其自己独特的方式,如上面各节中的
所述。例如,用于方法调用
个候选对象集不包括标记为
覆盖的方法(第7.4节),并且如果基类中的任何
方法不是基类中的方法也不是候选对象
(第7.6.5.1节)。

Each of these contexts defines the set of candidate function members and the list of arguments in its own unique way, as described in detail in the sections listed above. For example, the set of candidates for a method invocation does not include methods marked override (§7.4), and methods in a base class are not candidates if any method in a derived class is applicable (§7.6.5.1).

当我们查看7.4时:


对类型T中具有K个类型参数的名称N的成员查找的处理如下:

A member lookup of a name N with K type parameters in a type T is processed as follows:

•首先,确定一组名为N的可访问成员:

• First, a set of accessible members named N is determined:


  • 如果T是类型参数,则该集合是在指定为T的主要约束或次要约束(第10.1.5节)的每种类型中,名为N的

    个可访问成员的集合的集合,以及其中的N个可访问成员的集合。

  • If T is a type parameter, then the set is the union of the sets of
    accessible members named N in each of the types specified as a primary constraint or secondary constraint (§10.1.5) for T, along with the set of accessible members named N in object.

否则,该集合由T中所有名为N的可访问(§3.5)成员组成,包括继承的成员和对象中名为N的可访问成员。如果T是构造类型,则通过替换类型自变量来获得成员集
,如§10.3.2中所述。
包含替代修饰符的成员将从集合中排除。

Otherwise, the set consists of all accessible (§3.5) members named N in T, including inherited members and the accessible membersnamed N in object. If T is a constructed type, the set of members is obtained by substituting type arguments as described in §10.3.2. Members that include an override modifier are excluded from the set.

如果删除覆盖,则编译器在强制转换时会选择 Execute(string)重载该项目。

If you remove override the compiler picks the Execute(string) overload when you cast the item.

这篇关于C#方法重载解决方案未选择具体的通用替代的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆