以下程序产生此输出:
Foo<T> called
Process is terminated due to StackOverflowException.
因此,Foo(baz)
会调用通用Foo<T>
,但Bar(baz)
会递归并不调用Bar<T>
。
我在C#5.0和Microsoft .NET上。当非泛型方法是override
时,编译器似乎选择泛型方法而不是递归。
我在哪里可以找到有关此规则的解释?(我猜测编译器会在两种情况下选择递归。)
以下是整个计划:
using System;
namespace ConsoleApplication1 {
class Baz { }
abstract class Parent {
public abstract void Foo(Baz baz);
}
class Child : Parent {
void Bar<T>(T baz) {
Console.WriteLine("Bar<T> called");
}
public void Bar(Baz baz) {
Bar(baz);
}
void Foo<T>(T baz) {
Console.WriteLine("Foo<T> called");
}
public override void Foo(Baz baz) {
Foo(baz);
}
}
class Program {
static void Main(string[] args) {
var child = new Child();
child.Foo(null);
child.Bar(null);
Console.ReadLine();
}
}
}
答案 0 :(得分:5)
根据MSDN文档,优先考虑未被覆盖的方法签名。由于Foo的非泛型版本被覆盖,因此它会立即进入选择方法的优先级的底部。一般而言,下一步是选择最具体的方法并执行它。对于Bar方法,Bar(Baz baz)
方法在您的情况下将始终是最具体的。
重载解析是一种选择最佳解决方案的编译时机制 函数成员调用给定的参数列表和一组 候选职能成员。重载分辨率选择该功能 要在C#中的以下不同上下文中调用的成员:
- 调用invocation-expression中指定的方法(Section 7.5.5)。调用在object-creation-expression中命名的实例构造函数(第7.5.10.1节)。
- 通过元素访问调用索引器访问器(第7.5.6节)。调用表达式中引用的预定义或用户定义的运算符 (第7.2.3节和第7.2.4节)。
这些背景中的每一个都定义了 候选函数成员集和自己的参数列表 独特的方式,如上面列出的部分中详细描述的那样。 :用于 例如,方法调用的候选集不会 包括标记为覆盖的方法(第7.3节)和基础中的方法 如果派生类中的任何方法是,则class不是候选者 适用(第7.5.5.1节)。
我把我认为与你的问题有关的文字加粗了。
这是关于Stack Overflow的另一个问题,可能会有所帮助。它总体上讨论了方法解决方案。不涉及重写方法,但有助于填写我没有触及的一些过程。
答案 1 :(得分:1)
重载分辨率搜索继承链,在每个点查找定义的方法。
Child
定义void Foo<T>(T baz)
但未定义void Foo(Baz baz)
,因此选择了void Foo<T>(T baz)
。
一般来说,这是有道理的;在实际代码中如果Foo<T>(T baz)
与Foo(Baz baz)
传递Baz
的基础public new void Foo(Baz baz)
没有做同样的工作,那么您的设计会让人感到困惑,您应该选择一个新名称。< / p>
您可以使用public new virtual void Foo(Baz baz)
或Child
来强制进行覆盖,以强制在base.Foo(baz)
中定义覆盖(尽管此处需要进行中间步骤)层次结构,以便抽象方法有一个实现),可以调用Foo<Baz>(baz)
(调用基本实现)和/或> network_matrix
login mentions weight
[1,] "rtomayko" "author" "1"
> str(network_matrix)
chr [1, 1:3] "rtomayko" "author" "1"
- attr(*, "dimnames")=List of 2
..$ : NULL
..$ : chr [1:3] "login" "mentions" "weight"
> typeof(network_matrix)
[1] "character"
> g = graph.edgelist(network_matrix[,1:2], directed = TRUE)
Error in graph.edgelist(network_matrix[, 1:2], directed = TRUE) :
graph_from_edgelist expects a matrix with two columns
>
(调用泛型版)`,但最好避免这样的技巧
答案 2 :(得分:0)
也许它就像你实现类似的东西一样
void myMethod(long? l) { }
void myMethod(int? i) { }
使用null
调用它将使用int?
添加这个
void myMethod(short? i) { }
仍然使用null
调用它,代码将切换为short?
可能正在进行内部订单/优先级?
现在使用您的代码,我只是为了表明让编译器决定和程序员决定(显式调用)之间的区别
这是通用Baz
.method private hidebysig
instance void Bar<T> (
!!T baz
) cil managed
{
// Method begins at RVA 0x2060
// Code size 13 (0xd)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "Bar<T> called"
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: ret
} // end of method Child::Bar
您的实施
public void Bar(Baz baz) {
Bar(baz);
}
给这个
.method public hidebysig
instance void Bar (
class ConsoleApplication1.Baz baz
) cil managed
{
// Method begins at RVA 0x206e
// Code size 10 (0xa)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: call instance void ConsoleApplication1.Child::Bar(class ConsoleApplication1.Baz)
IL_0008: nop
IL_0009: ret
} // end of method Child::Bar
这一个
public void Bar(Baz baz)
{
Bar<Baz>(baz);
}
给这个
.method public hidebysig
instance void Bar (
class ConsoleApplication1.Baz baz
) cil managed
{
// Method begins at RVA 0x206e
// Code size 10 (0xa)
.maxstack 8
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: call instance void ConsoleApplication1.Child::Bar<class ConsoleApplication1.Baz>(!!0)
IL_0008: nop
IL_0009: ret
} // end of method Child::Bar