C # не выводит перегруженный метод через возвращаемый тип

#c# #overloading

#c# #перегрузка

Вопрос:

Я пишу программку на C # для обхода каталога и предоставляю мне список файлов, дата которых в последней строке CSV меньше текущей даты. Поскольку это программка, я на самом деле не трачу слишком много времени на то, чтобы сделать код очень чистым или что-то в этом роде — но это все вопрос мнения, я полагаю.

Любопытным является следующий набор фрагментов кода. Три статических метода, все в одном классе.

    public static DateTime dateStringConverter(string mmddyyyy, char delim='/')
    {
            string[] date = mmddyyyy.Split(delim);
            DateTime fileTime = new DateTime(Convert.ToInt32(date[2]), Convert.ToInt32(date[0]), Convert.ToInt32(date[1]));
            return fileTime;
    }

        public static string dateStringGetter()
        {
            string sYear = DateTime.Now.Year.ToString();
            string sMonth = DateTime.Now.Month.ToString().PadLeft(2, '0');
            string sDay = DateTime.Now.Day.ToString().PadLeft(2, '0');
            return sMonth   '/'   sDay   '/'   sYear;
        }

        public static DateTime dateStringGetter()
        {
            string datestring = dateStringGetter();
            return dateStringConverter(datestring);
        }
  

В сообщении об ошибке говорится:

 Error   1   Type 'Poller.Program' already defines a member called 
'dateStringGetter' with the same parameter types    
  

Проблемный метод — это вторая перегруженная копия dateStringGetter() , которая, конечно, имеет те же типы параметров, что и вторая версия (none), но имеет два совершенно разных возвращаемых типа. Один из них — DateTime, а другой — string . Версия с возвращаемым типом DateTime — в строке с неправильным кодированием — вызывает версию dateStringGetter() со строковым типом.

Разве это не любопытно? Что C # не будет перегружать методы, основанные только на возвращаемом типе? Я думаю, что я выполнил перегрузку библиотеками, которые автоматически определят возвращаемый тип, который я хочу, на основе вызова — но я не уверен. Что-то в этом не так.

Итак, я полагаю, C # не перегружает возвращаемые типы?

Комментарии:

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

Ответ №1:

Итак, я полагаю, C # не перегружает возвращаемые типы?

Нет, действительно, это не так. Возвращаемый тип не является частью подписи.

Из раздела 3.6 спецификации C # 5 (выделение мое):

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

и

Перегрузка методов позволяет классу, структуре или интерфейсу объявлять несколько методов с одинаковым именем при условии, что их сигнатуры уникальны в этом классе, структуре или интерфейсе.

И дополнительно (для полноты):

Хотя out ref модификаторы параметров и считаются частью подписи, члены, объявленные в одном типе, не могут отличаться по сигнатуре только на ref и out .

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

В качестве примечания, ваши методы в настоящее время не выполняются.Соглашения об именовании сетей — и вы должны использовать стандартные методы форматирования / синтаксического анализа вместо того, чтобы использовать свои собственные.

Комментарии:

1. Я не знал этой последней части (хотя это имеет смысл). Отличная информация!

2. Серьезно — 57 секунд до ответа ?! FGITW, конечно, Джон. Большое вам спасибо! Я проведу некоторые исследования. СЕТЕВЫЕ соглашения об именах и внесите некоторые изменения в мой (не неаккуратный) стиль кодирования.

Ответ №2:

Нет, C # (как и C до него) не допускает перегрузки, когда единственное различие заключается в типе возвращаемого значения.

Большая проблема здесь в том, какой из них вы вызываете, если не присваиваете возвращаемое значение? Какой из них вы вызываете, если оба типа можно преобразовать в присваиваемое возвращаемое значение? Это очень неоднозначно и поэтому недопустимо.

Ответ №3:

На основе «programlet для обхода каталога и предоставления мне списка файлов, дата которых в последней строке CSV меньше текущей даты. Поскольку это программка, я на самом деле не трачу слишком много времени на то, чтобы сделать код очень чистым или что-то в этом роде» Я предлагаю что-то похожее на следующее, которое я использовал в прошлом. Примите это или оставьте.

Что он делает: укажите корневой каталог, функция получает все файлы в каталоге заданного типа (для ваших временных требований измените files.add(…) в соответствии с вашими критериями)

Только оставляя это здесь в качестве альтернативы вашей работе, поскольку вы сказали, что не хотите тратить на это много времени.

     var data = GetAllFilesOfType('c:rootpath', 'csv')
/// <summary>
    /// Gets files of specified type and appends them to the file list.
    /// </summary>
    /// <param name="basepath">Starting file path</param>
    /// <param name="type">File type - Do not include prefix ('txt' instead of '*.txt</param>
    /// <returns>Returns results of WalkDirectoryTree</returns>
    public static IEnumerable<FileInfo[]> GetAllFilesOfType(string basepath, string type)
    {
        var root = new DirectoryInfo(basepath);
        return WalkDirectoryTree(root, type);
    }


/// <summary>
    /// Recursively gets all files from a specified basepath (provided by GetAllFilesOfType)
    /// and appends them to a file list. This method reports all errors, and will break on
    /// things like security errors, non existant items, etc.
    /// </summary>
    /// <param name="root">Initially specified by calling function, set by recursive walk</param>
    /// <param name="type">File type that is desired. Do not include prefix ('txt' instead of '*.txt')</param>
    /// <returns></returns>
    private static List<FileInfo[]> WalkDirectoryTree(DirectoryInfo root, string type)
    {
        var files = new List<FileInfo[]>();

        //Traverse entire directory tree recursively - Will break on exception
        var subDirs = root.GetDirectories();
        foreach (var data in subDirs.Select(dirInfo => WalkDirectoryTree(dirInfo, type)).Where(data => data.Count > 0))
        {
            files.AddRange(data);
        }
        //If any file is found, add it to the file list
        if (root.GetFiles(string.Format("*.{0}", type)).Length > 0)
        {
            files.Add(root.GetFiles(string.Format("*.{0}", type)));
        }
        //Kicks the file list up a level until it reaches root, then returns to calling function
        return files;
    }
  

Ответ №4:

К сожалению, всегда есть способ поставить его на место:

 class Program
{
    static void Main(string[] args)
    {
        object stringDate = "";
        object dateTime = new DateTime();
        DateUtils.DateStringGetter(ref stringDate);
        DateUtils.DateStringGetter(ref dateTime);
    }
}

public static class DateUtils
{
    private static DateTime DateStringConverter(string mmddyyyy, char delim = '/')
    {
        string[] date = mmddyyyy.Split(delim);
        DateTime fileTime = new DateTime(Convert.ToInt32(date[2]), Convert.ToInt32(date[0]),
            Convert.ToInt32(date[1]));
        return fileTime;
    }

    public static void DateStringGetter(ref object date)
    {
        string sYear = DateTime.Now.Year.ToString();
        string sMonth = DateTime.Now.Month.ToString().PadLeft(2, '0');
        string sDay = DateTime.Now.Day.ToString().PadLeft(2, '0');

        if (date is String)
        {
            date = sMonth   '/'   sDay   '/'   sYear;
        }

        if (date is DateTime)
        {
            date = DateStringConverter(sMonth   '/'   sDay   '/'   sYear);
        }

    }
}
  

Комментарии:

1. Это отличная идея! Спасибо за отличный ответ.

Ответ №5:

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

Ответ №6:

Правильно, C# не позволяет перегружать методы только для возвращаемых типов.

Подумайте, что произойдет, если я просто вызову dateStringGetter() без присвоения возвращаемого значения.

Какой метод я вызвал?