c#不会根据参数类型(继承)选择我想要的函数
本文关键字:选择 选择我 我想要 函数 继承 类型 参数 | 更新日期: 2023-09-27 18:07:54
我不知道如何解释这一点,所以我将展示我的示例并详细说明。
using System;
namespace Demo
{
static class Program
{
static void Main()
{
var test = new ExampleClass(new Bar());
Console.WriteLine(test);
}
}
class ExampleClass {
public Foo _foo;
public ExampleClass(Bar bar)
{
_foo = bar;
}
public override String ToString() {
return print(_foo);
}
String print(Bar bar) {
return bar.Name;
}
String print(Foo foo) {
return foo.ToString();
}
}
class Bar : Foo
{
public String Name;
}
class Foo
{ }
}
这行不通。
虽然我在声明中看到_foo
的类型是Foo
,但它也可以是Bar
,因为它继承自Foo
。
我的问题是
为什么编译器看不到_foo
的实际类型?
为什么print(Foo)
总是执行,即使类型是Foo
的派生类?
编辑
编辑了我的示例代码,因为它仍然包含了我的原始代码的大部分。
感谢Anthony Pegram的例子
您的代码并没有很好地展示您的问题,因为您引入了一个SyntaxNode
类型的字段,而没有显示它与BaseClass/BaseClassExtension
类型层次结构的关系。但当给出可理解的类型时,仍然有一些问题是可以回答的。
我的问题是:为什么。net运行时看不到originalNode的实际类型?为什么它总是去打印(BaseClass),即使类型是baseclassextion ?
. net运行时并不是决定使用哪个重载的。这是编译器的一个属性,它使用它所拥有的关于变量(或字段、属性)类型的信息来确定使用哪个重载。
一个简单的演示。假设我们有
class Foo { }
class Bar : Foo { }
void Do(Foo foo)
{
Console.WriteLine("Foo overload");
}
void Do(Bar bar)
{
Console.WriteLine("Bar overload");
}
然后是代码
Foo foo = new Bar();
Do(foo);
你有一个类型为Foo
的变量,它恰好引用了一个类型为Bar
的对象。编译器在编译时发出代码来调用Foo
重载,因为这是它所知道的,坦率地说,这是您告诉它要做的。(事实上,我们在前一行中将它实例化为Bar
类型的对象并不是特别相关。在下一行,只要考虑foo
可能来自的任何地方,我们所知道的是变量foo
的类型是Foo
。
如果您希望在运行时使用更具体的重载,您可以探索双重分派机制,例如访问者模式。我不特别推荐的另一种方法是通过dynamic
关键字在运行时确定类型(如果问题被很好地理解,通常有更好的替代方法,但有时它适合)。
Foo foo = new Bar();
Do((dynamic)foo);
动态在运行时的语义是你可以在你自己的时间研究的东西,但这有效地产生了你似乎想要的结果。
我尝试了一下,但是如果类SyntaxNode派生自类baseclassextion,则它可以像预期的那样工作—因此很难从您向我们展示的代码中判断出问题所在。
这是我所期望的:
using System;
namespace Demo
{
static class Program
{
static void Main()
{
var test = new myNode();
Console.WriteLine(test);
}
}
class myNode
{
public SyntaxNode originalNode = new SyntaxNode{Name = "SyntaxNode"};
public override string ToString()
{
return print(originalNode); // This calls print(BaseClassExtention Class)
}
string print(BaseClassExtention Class) // <= This gets called.
{
return Class.Name;
}
string print(BaseClass b)
{
return b.ToString();
}
}
class BaseClass
{}
class BaseClassExtention : BaseClass
{
public string Name { get; set; }
}
class SyntaxNode: BaseClassExtention
{
}
}
看起来您期望根据originalNode
的运行时类型选择print
。c#在编译时选择函数调用——print
不是虚方法,所以调用必须在编译时解析。
所以你有
public SyntaxNode originalNode;
string print(BaseClassExtention Class)...
string print(BaseClass base)...
在编译时将选择两个打印函数中的一个(基于SyntaxNode
是BaseClass
还是BaseClassExtension
)。如果SyntaxNode
源自BaseClassExtension
,则使用string print(BaseClassExtention Class)
版本(因为它比BaseClass
更具体,甚至两者都可以使用),否则使用另一个版本。
如果你想要基于originalNode
的运行时类型的行为不同,你需要调用originalNode
的一些虚拟方法作为print
的一部分,或者手动检查类型并在print
方法中做一些事情。