.NET Console.WriteLine Метод ToString Поведение - PullRequest
0 голосов
/ 07 февраля 2019

Как я знаю. .NET Console.WriteLine метод вызывает метод ToString класса.В приведенном ниже коде вызов Console.WriteLine (object) и вызов Console.WriteLine (object.ToString ()) производят разные выходные данные.Если в методе ToString в приведенном ниже коде добавлено ключевое слово override, выходные данные становятся одинаковыми.Но мне интересно, почему выходы отличаются в первом случае.

Вывод программы:

TestOverrideConsole.Program (Имя класса)

Привет из программы

class Program
{
    static void Main(string[] args)
    {
        Program p = new Program();
        Console.WriteLine(p);
        Console.WriteLine(p.ToString());

        Console.ReadLine();
    }

    public String ToString()
    {
        return "Hello from Program";
    }
}

Ответы [ 3 ]

0 голосов
/ 07 февраля 2019

Console.WriteLine(p) вызывает ToString метод объекта, так как метод ToString не переопределяется.

public String ToString()

Этот метод скрывает ToString метод базового класса и не переопределяет его.Это причина, почему результаты отличаются.Чтобы правильно переопределить метод ToString, необходимо добавить ключевое слово override в объявление метода.

0 голосов
/ 07 февраля 2019

Я изменил ваш код, чтобы он компилировался, вы можете проверить его здесь ,

using System;

public static class Program
{
    static void Main(string[] args)
    {
        var p = new P();
        Console.WriteLine(p);
        Console.WriteLine(p.ToString());
    }
}

class P
{
    public String ToString()
    {
        return "Hello from Program";
    }
}

Вы заметите, что компилятор выдает это предупреждение

предупреждение CS0114: «P.ToString ()» скрывает унаследованный член «object.ToString ()».Чтобы текущий член переопределил эту реализацию, добавьте ключевое слово override.В противном случае добавьте новое ключевое слово.

, которое, как мне кажется, само собой разумеется.

Когда WriteLine() вызывает ToString(), он обращается к виртуальному члену, который вы не переопределили.

0 голосов
/ 07 февраля 2019

Когда вы переопределяете метод, вы в основном помещаете новую реализацию в «слот» 1 , который уже был определен вашим базовым классом для этого метода.Когда вы скрываете метод (не используете переопределение), вы берете имя, которое использовал ваш базовый класс, и присваиваете это имя другому"слоту".

Когда компиляторвыполняет разрешение имени / перегрузки, в основном он пытается решить, через какой «слот» направить вызов метода (потому что из-за перегрузки у вас может быть несколько методов с одинаковыми именами, но у них будут разные «слоты»).

При компиляции Console.WriteLine единственный слот, который компилятор может выбрать для ToString, - это тот, который Object объявил для его ToString метод.Так что это единственный метод, который он когда-либо будет вызывать 2 .


1 Я использую здесь «слот», потому что пока вы не найдетеон использовался в C # Spec, насколько я помню, на уровне CLR методы затенения помечены newslot.

2 Не уверен на 100%, что он вызывает буквально ToString, а не проходить через любое количество косвенных указаний, но достаточно сказать, что это так.

...