简体   繁体   English

C#不通过返回类型推断重载方法

[英]C# not inferring overloaded method via return type

I'm writing a C# programlet to crawl a directory and give me a listing of files whose date in the last CSV line is less than the current date. 我正在编写一个C#程序集来抓取目录并给我一个文件列表,其中最后一行CSV行中的日期小于当前日期。 Since this is a programlet, I'm not really spending too much time making the code very clean or anything -- but that's all a matter of opinion, I suppose. 由于这是一个程序员,我实际上并没有花太多时间使代码非常干净或任何东西 - 但我认为这完全是一个意见问题。

The curious thing is the following set of code snippets. 好奇的是以下一组代码片段。 Three static methods all in the same class. 三个静态方法都在同一个类中。

   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);
        }

The error message says: 错误消息说:

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

The problem method is the second overloaded copy of dateStringGetter(), which of course has the same parameter types as the second version (none) but has two completely different return types. 问题方法是dateStringGetter()的第二个重载副本,它当然具有与第二个版本(无)相同的参数类型,但有两个完全不同的返回类型。 One is DateTime and the other is string. 一个是DateTime,另一个是字符串。 The version with the DateTime return type -- in a string of bad coding -- calls the version of dateStringGetter() with a string type. 具有DateTime返回类型的版本(在编码错误的字符串中)使用字符串类型调用dateStringGetter()的版本。

Isn't this curious? 这不是很好奇吗? That C# will not overload methods based on return type alone? 那个C#不会单独根据返回类型重载方法吗? I think I've done overloading with libraries that will automatically detect the return type I want based on the call -- but I'm not sure. 我想我已经完成了库的重载,它会根据调用自动检测我想要的返回类型 - 但我不确定。 Something doesn't feel right about this. 对此我感觉不对劲。

So I suppose C# does not overload return types? 所以我认为C#不会超载返回类型?

So I suppose C# does not overload return types? 所以我认为C#不会超载返回类型?

No, indeed it doesn't. 不,确实没有。 The return type isn't part of the signature. 返回类型不是签名的一部分。

From section 3.6 of the C# 5 specification (emphasis mine): 从C#5规范的第3.6节(强调我的):

The signature of a method consists of the name of the method, the number of type parameters and the type and kind (value, reference, or output) of each of its formal parameters, considered in the order left to right. 方法的签名包括方法的名称,类型参数的数量以及每个形式参数的类型和种类(值,引用或输出),按从左到右的顺序考虑。 For these purposes, any type parameter of the method that occurs in the type of a formal parameter is identified not by its name, but by its ordinal position in the type argument list of the method. 出于这些目的,在形式参数类型中出现的方法的任何类型参数不是通过其名称来标识,而是通过其在方法的类型参数列表中的序号位置来标识。 The signature of a method specifically does not include the return type , the params modifier that may be specified for the right-most parameter, nor the optional type parameter constraints. 方法的签名特别不包括返回类型 ,可以为最右边的参数指定的params修饰符,也不包括可选的类型参数约束。

and

Overloading of methods permits a class, struct, or interface to declare multiple methods with the same name, provided their signatures are unique within that class, struct, or interface. 方法的重载允许类,结构或接口声明具有相同名称的多个方法,前提是它们的签名在该类,结构或接口中是唯一的。

And additionally (for completeness): 另外(为了完整性):

Although out and ref parameter modifiers are considered part of a signature, members declared in a single type cannot differ in signature solely by ref and out . 虽然outref参数修饰符被认为是签名的一部分,但在单一类型中声明的成员只能通过refout在签名上有所不同。

Aside from anything else, this restriction helps with readability - it can be hard enough to tell which overload is being called sometimes even when they vary by parameters - it would be even worse if methods could be overloaded by return type. 除了其他任何东西之外,这种限制有助于提高可读性 - 即使它们因参数而异,也很难分辨出哪些重载被调用 - 如果方法可能被返回类型重载,那就更糟了。 In this case it doesn't even make sense for the methods to be overloaded, as they do opposite things . 在这种情况下,对于重载方法甚至没有意义,因为它们做了相反的事情 You should only overload a method if all the overloads perform the same basic task. 如果所有重载执行相同的基本任务,则只应重载方法。

As a side note, your methods don't currently follow .NET naming conventions - and you should be using standard formatting/parsing methods instead of rolling your own. 作为旁注,您的方法当前不遵循.NET命名约定 - 您应该使用标准格式化/解析方法而不是滚动自己的方法。

No, C# (like C++ before it) does not allow an overload where the only difference is in the return type . 不,C#(比之前的C ++)不允许重载,其中唯一的区别在于返回类型

The big problem here is which one do you call if you don't assign the return value? 这里的一个大问题是,如果你没有分配返回值,你会打电话给哪一个? Which one do you call if both types are castable to the return value assignment? 如果两种类型都可以转换为返回值赋值,那么您可以调用哪一个? Its highly ambiguous, and so not allowed. 它高度模糊,所以不允许。

Based on "programlet to crawl a directory and give me a listing of files whose date in the last CSV line is less than the current date. Since this is a programlet, I'm not really spending too much time making the code very clean or anything" I propose something similar to the following which I've used in the past. 基于“用于抓取目录的程序集,并给我一个在最后一行CSV行中的日期小于当前日期的文件列表。由于这是一个程序员,我实际上并没有花太多时间使代码非常干净或者什么“我提出类似于我过去使用的以下内容。 Take it or leave it. 要么接受,要么离开它。

What it does: Specify a root directory, function gets all files within directory of given type (for your time requirement, modify files.add(...) to match your criteria) 作用:指定根目录,函数获取给定类型的目录中的所有文件(根据您的时间要求,修改files.add(...)以符合您的条件)

Only leaving this here as an alternative to your work since you said you don't want to spend much time on it. 只留下这里作为你工作的替代品,因为你说你不想花太多时间在它上面。

    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;
    }

There is always a way to hammer it into place, unfortunately: 不幸的是,总有一种方法可以将它锤到位:

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);
        }

    }
}

您不能只为返回类型提供两种不同的方法,因为代码无法推断哪些应该是返回类型。

Correct, C# does not let you overload methods on return types only. 正确, C#不允许您仅对返回类型重载方法。

Consider what happens if I just call dateStringGetter() without assignment of return value. 考虑如果我只调用dateStringGetter()而不分配返回值会发生什么。

Which method have I called? 我打过哪种方法?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM