嵌套调用中的C#重载

嵌套调用中的C#重载,c#,overloading,C#,Overloading,鉴于以下情况: class A { public void Foo(object o) { Console.WriteLine("general"); } public void Foo(B o) { Console.WriteLine("specific"); } } class B { A a = new A(); public void CallFoo(object x) {

鉴于以下情况:

class A
{
    public void Foo(object o)
    {
        Console.WriteLine("general");
    }
    public void Foo(B o)
    {
        Console.WriteLine("specific");
    }
}

class B
{
    A a = new A();
    public void CallFoo(object x)
    {
        a.Foo(x);
    }

    public static void Main()
    {
       B b = new B();
       b.CallFoo(b);
       b.a.Foo(b);
    }
}
我观察到以下结果:

general
specific

很自然,我很困惑。这里发生了什么?

每一个
b.CallFoo
都将导致打印general,因为
CallFoo
对象
作为参数。正确的方法重载是在编译过程中确定的,因此这里编译器只能选择常规方法

通过使用
dynamic
as
CallFoo
参数类型,可以在运行时强制选择重载:

public void CallFoo(dynamic x)
{
    a.Foo(x);
}
或者您可以自己编写逻辑,在
B.CallFoo
中:

public void CallFoo(object x)
{
    if (x is B)
    {
        a.Foo((B)x);
    }
    else
    {
        a.Foo(x);
    }
}
public void Foo(object o)
{
    if (o is B)
    {
        Foo((B)o);
    }
    else
    {
        Console.WriteLine("general");
    }
}
或者直接在
a.Foo
中:

public void CallFoo(object x)
{
    if (x is B)
    {
        a.Foo((B)x);
    }
    else
    {
        a.Foo(x);
    }
}
public void Foo(object o)
{
    if (o is B)
    {
        Foo((B)o);
    }
    else
    {
        Console.WriteLine("general");
    }
}

每个
b.CallFoo
都将导致打印general,因为
CallFoo
object
作为参数。正确的方法重载是在编译过程中确定的,因此这里编译器只能选择常规方法

通过使用
dynamic
as
CallFoo
参数类型,可以在运行时强制选择重载:

public void CallFoo(dynamic x)
{
    a.Foo(x);
}
或者您可以自己编写逻辑,在
B.CallFoo
中:

public void CallFoo(object x)
{
    if (x is B)
    {
        a.Foo((B)x);
    }
    else
    {
        a.Foo(x);
    }
}
public void Foo(object o)
{
    if (o is B)
    {
        Foo((B)o);
    }
    else
    {
        Console.WriteLine("general");
    }
}
或者直接在
a.Foo
中:

public void CallFoo(object x)
{
    if (x is B)
    {
        a.Foo((B)x);
    }
    else
    {
        a.Foo(x);
    }
}
public void Foo(object o)
{
    if (o is B)
    {
        Foo((B)o);
    }
    else
    {
        Console.WriteLine("general");
    }
}

这绝对是正确的行为。重载解析通常发生在编译时,而不是运行时。(除非您正在进行一些时髦的反射或编译lambda表达式)

在代码中,.NET在编译时只知道x是一个对象:

public void CallFoo(object x)
{
    a.Foo(x);   // <--- Gets wired up to Foo(object o) as x is declared as an object!
}
public void CallFoo(对象x)
{

a、 Foo(x);//这绝对是正确的行为。重载解析通常发生在编译时,而不是运行时。(除非您正在进行一些时髦的反射或编译lambda表达式)

在代码中,.NET在编译时只知道x是一个对象:

public void CallFoo(object x)
{
    a.Foo(x);   // <--- Gets wired up to Foo(object o) as x is declared as an object!
}
public void CallFoo(对象x)
{
a、 Foo(x);//b.CallFoo(对象x)
正在作为对象的类型传递
如果不选中instanceof,它将被视为对象类型
如果将A.Foo的功能更改为:

public void Foo(object o){
        B test = o as B;
    if(test == null){
        Console.WriteLine("general");
    }else
{
Console.WriteLine("specific");
}
}
你将得到你所期望的

b.CallFoo(对象x) 正在作为对象的类型传递 如果不选中instanceof,它将被视为对象类型 如果将A.Foo的功能更改为:

public void Foo(object o){
        B test = o as B;
    if(test == null){
        Console.WriteLine("general");
    }else
{
Console.WriteLine("specific");
}
}

您将得到您所期望的

这是期望的行为。在您的第一次调用
b.CallFoo(b)
中,您正在调用方法
b.CallFoo(object)
,该方法反过来调用基类的
Foo(object)


在第二次调用中,您直接从类A访问
Foo(B)
方法,并且还传递类型为B的var B,这是预期的行为。在第一次调用
B.CallFoo(B)
中,您调用的是方法
B.CallFoo(object)
,该方法反过来调用基类的
Foo(对象)


在第二个调用中,您直接从类A访问
Foo(B)
方法,并且还传递类型为B

的var B,这都是关于方法签名的。B.CallFoo()接受一个对象,自然地,它调用期望对象的重载。下一个调用是输入一个类型为B的强类型对象,编译器知道您想要使用接受类型为B的对象的重载

如果希望根据类型有条件地调用重载,则必须自己完成这项工作

例如:

class B
{
    A a = new A();
    public void CallFoo(object x)
    {
        if (x.GetType() == typeof(B))
        {
            a.Foo((B)x);
        }
        else
        {
            a.Foo(x);
        }            
    }

    public static void Main()
    {
        B b = new B();
        b.CallFoo(b);
        b.a.Foo(b);
    }
}

这都是关于方法签名的。b.CallFoo()接受一个对象,自然,它调用期望对象的重载。下一个调用是输入一个类型为b的强类型对象,编译器知道您想要使用接受类型为b的对象的重载

如果希望根据类型有条件地调用重载,则必须自己完成这项工作

例如:

class B
{
    A a = new A();
    public void CallFoo(object x)
    {
        if (x.GetType() == typeof(B))
        {
            a.Foo((B)x);
        }
        else
        {
            a.Foo(x);
        }            
    }

    public static void Main()
    {
        B b = new B();
        b.CallFoo(b);
        b.a.Foo(b);
    }
}
1) b.CallFoo(b); CallFoo将对象类型作为参数。然后将该对象传递给Foo,从而调用Foo(对象o)

2) b.a.Foo(b); Foo(bo)将被调用,因为传递的对象的类型为B。

1)B.CallFoo(B); CallFoo将对象类型作为参数。然后将该对象传递给Foo,从而调用Foo(对象o)

2) b.a.Foo(b);
Foo(bo)将被调用,因为传递的对象是类型B。

对我来说似乎很明显。
CallFoo
采用对象参数,因此
a.Foo(x)
将解析为
Foo(object)
B.a.Foo(B)
可以调用
Foo(B)
因为大家都知道b在那里总是b型的。我也不确定这里是否有问题……对我来说似乎很明显。
CallFoo
接受一个object参数,因此
a.Foo(x)
将解析为
Foo(object)
b.a.Foo(b)
可以调用
Foo(b)
因为我们知道b总是b类型。我也不确定这里是否有问题。这正是我不理解的地方——重载的编译时解析。不幸的是,在这种情况下,由于交叉编译问题,我不能将x定义为动态的。所以……我必须使用“is”构造,这正是我试图避免的。谢谢!这正是我不理解的一点——重载的编译时解析。不幸的是,在这种情况下,由于交叉编译问题,我不能将x定义为动态的。所以…我必须使用“is”构造,这正是我试图避免的。谢谢!