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的例子

c#不会根据参数类型(继承)选择我想要的函数

您的代码并没有很好地展示您的问题,因为您引入了一个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)...

在编译时将选择两个打印函数中的一个(基于SyntaxNodeBaseClass还是BaseClassExtension)。如果SyntaxNode源自BaseClassExtension,则使用string print(BaseClassExtention Class)版本(因为它比BaseClass更具体,甚至两者都可以使用),否则使用另一个版本。

如果你想要基于originalNode的运行时类型的行为不同,你需要调用originalNode的一些虚拟方法作为print的一部分,或者手动检查类型并在print方法中做一些事情。