Перегрузка метода в C# ведет себя неожиданно при использовании ключевого слова params

Хорошо, вернемся к основам. Мне интересно, как правильно перегрузить метод с params аргумент.

Вот мой сценарий. Я начинаю с моего обычного метода:

public void MyMethod(MyObject mo)
{
    // method body
}

И я создал для него перегрузку, которая выглядит так:

public void MyMethod(MyObject mo, params string[] fields)
{
    // new method body

    MyMethod(mo);
}

Очевидное намерение для MyMethod(new MyObject()); выполнить оригинальный метод и MyMethod(new MyObject(), "field0"/*, etc...*/); выполнить перегруженный метод. Но дело не в этом.

На самом деле происходит то, что MyMethod(new MyObject()); выполняет перегруженный метод!

Я не понимаю этого. В этом типе сценария, как мне выполнить оригинальный метод?

ОБНОВЛЕНИЕ с актуальным кодом

Итак, вот фактический код, который производит описанное поведение.

Class1Base.cs:

public class Class1Base
{
    public virtual void MyMethod(MyObject ob)
    {
        Console.WriteLine("Called Class1Base");
    }
}

Class1.cs:

public class Class1 : Class1Base
{
    public override void MyMethod(MyObject ob)
    {
        Console.WriteLine("called overridden method");
    }

    public void MyMethod(MyObject ob, params string[] fields)
    {
        Console.WriteLine("called OVERLOADED method");
    }
}

MyObject.cs:

public class MyObject
{
    public int Id { get; set; }
    public string Description { get; set; }
}

Затем, когда я выполняю этот код следующим образом:

var myClass = new Class1();
var myObject = new MyObject();
myClass.MyMethod(myObject);
myClass.MyMethod(null);
myClass.MyMethod(null, "string");

Консоль показывает:

called OVERLOADED method
called OVERLOADED method
called OVERLOADED method

Я бы ожидал, что это покажет:

called overridden method
called overridden method
called OVERLOADED method

Почему не так?

1 ответ

Решение

Я не думаю, что вы рассказываете нам всю историю. Раздел 7.3.5.2 спецификации C# 5 (под названием "Лучший функциональный член") говорит частично:

• В противном случае, если MP применим в своей обычной форме, а MQ имеет массив параметров и применим только в расширенной форме, тогда MP лучше, чем MQ.

Это, похоже, имеет место здесь, так как params Версия должна быть "расширена" до массива нулевой длины. И на самом деле, пробуя ваш код локально, вы получите ожидаемый результат вызоваparams версия.

Обновление: в ответ на ваши изменения ответ теперь ясен: вы вызываете методы из Class1, что означает, что при выполнении разрешения перегрузки методы, помеченные как override не рассматриваются изначально. И поскольку применим не-переопределенный метод (хотя и в расширенном виде), то этот метод выбран.

В частности, раздел 7.6.5.1 читать частично:

• Набор методов-кандидатов сокращен, чтобы содержать только методы из наиболее производных типов: для каждого метода CF в наборе, где C - это тип, в котором объявлен метод F, все методы, объявленные в базовом типе C, удаляются. из набора.

Базовый класс MyMethod() исключен из набора кандидатов, поэтому алгоритм не будет выбран.


Точное обоснование такого поведения состоит в том, чтобы избежать проявления проблемы "хрупкого базового класса". Предположим, у нас была следующая иерархия классов:

class A
{
}

class B : A
{
    public void MyMethod(object o) { }
}

И следующий call-сайт:

new B().MyMethod("a string");

Это, очевидно, решит MyMethod() это занимает object, Но теперь предположим, что создатель A (возможно, кто работает в другой команде) решает A должен иметь MyMethod(), тоже. Поэтому они меняют свой класс:

class A
{
    public void MyMethod(string s);
}

А теперь представьте, что произойдет, если мы не исключим методы из базовых типов. Ваш звонок, который первоначально был разрешен B.MyMethod() вдруг решил бы A.MyMethod() (так как string это лучшее совпадение.) Дизайнеры C# не хотели позволять другому человеку в совершенно другой команде молча менять смысл вашего кода.

Для получения дополнительной информации о хрупких проблемах базового класса в блоге Эрика Липперта (старый) есть несколько постов на эту тему. Просто немного поищите.

Другие вопросы по тегам