#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()
без присвоения возвращаемого значения.
Какой метод я вызвал?