【问题标题】:C# not inferring overloaded method via return typeC# 不通过返回类型推断重载方法
【发布时间】:2014-06-23 18:44:16
【问题描述】:

我正在编写一个 C# 小程序来抓取一个目录并给我一个文件列表,这些文件在最后 CSV 行中的日期小于当前日期。由于这是一个小程序,我并没有花太多时间使代码非常干净或任何东西——但我想这都是见仁见智的问题。

奇怪的是下面这组代码sn-ps。三个静态方法都在同一个类中。

   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() 的第二个重载副本,它当然与第二个版本具有相同的参数类型(无),但具有两个完全不同的返回类型。一个是 DateTime,另一个是字符串。具有 DateTime 返回类型的版本——在一个错误编码的字符串中——调用具有字符串类型的 dateStringGetter() 版本。

这不是很好奇吗? C# 不会仅基于返回类型重载方法吗?我想我已经完成了库的重载,这些库将根据调用自动检测我想要的返回类型——但我不确定。对此感觉有些不对劲。

所以我想 C# 不会重载返回类型?

【问题讨论】:

  • 简单 - 你不能有两种方法,只是返回类型不同。使用不同的名称。

标签: c# overloading


【解决方案1】:

所以我想 C# 不会重载返回类型?

不,确实没有。返回类型不是签名的一部分。

来自 C# 5 规范的第 3.6 节(重点是我的):

方法的签名由方法的名称、类型参数的数量以及每个形式参数的类型和种类(值、引用或输出)组成,按从左到右的顺序考虑。出于这些目的,出现在形式参数类型中的方法的任何类型参数都不是通过其名称来标识的,而是通过其在方法的类型参数列表中的序号位置来标识的。 方法的签名具体不包括返回类型、可以为最右边的参数指定的params 修饰符,也不包括可选的类型参数约束。

方法的重载允许类、结构或接口声明多个具有相同名称的方法,前提是它们的签名在该类、结构或接口中是唯一的。

另外(为了完整性):

尽管outref 参数修饰符被视为签名的一部分,但在单一类型中声明的成员不能仅在签名上因refout 而不同。

除此之外,此限制有助于提高可读性——有时即使它们因参数而异,也很难分辨出调用了哪个重载——如果方法可以通过返回类型重载,那就更糟了。在这种情况下,重载方法甚至没有意义,因为它们会做相反的事情。只有当所有重载都执行相同的基本任务时,您才应该重载一个方法。

附带说明一下,您的方法目前不遵循 .NET 命名约定 - 您应该使用标准的格式化/解析方法,而不是使用自己的方法。

【讨论】:

  • 我不知道最后一部分(尽管它是有道理的)。很棒的信息!
  • 说真的——还有 57 秒才能得到答案?! FGITW 肯定的,乔恩。非常感谢!我将对 .NET 命名约定进行一些研究,并对我的(非草率的)编码风格进行一些更改。
【解决方案2】:

不,C#(就像之前的 C++)不允许重载,唯一的区别在于返回类型

这里最大的问题是,如果你不分配返回值,你会调用哪一个?如果这两种类型都可以转换为返回值赋值,你会调用哪一种?它非常模棱两可,因此不允许。

【讨论】:

    【解决方案3】:

    基于“小程序爬取目录并给我最后 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);
              }
      
          }
      }
      

      【讨论】:

      • 这是个好主意!感谢您的出色回答。
      【解决方案5】:

      您不能仅针对返回类型有两种不同的方法,因为代码无法推断出哪个应该是返回类型。

      【讨论】:

        【解决方案6】:

        正确,C# 不允许您仅在返回类型上重载方法。

        考虑一下如果我只调用dateStringGetter() 而不分配返回值会发生什么。

        我调用了哪个方法?

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-01-13
          • 2012-08-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-03-05
          • 2021-06-11
          相关资源
          最近更新 更多