【问题标题】:Recursive overload method with derived parameter [duplicate]具有派生参数的递归重载方法
【发布时间】:2020-03-18 21:06:56
【问题描述】:

Can anyone explain how which overloaded method is chosen when options only differ by a parameter type being derived? 例如以下代码:

using System;

public class Program
{
    public static void LogException(AggregateException aggrException, string message)
    {
        Console.WriteLine(string.Format("{0} Inner exceptions on following logs.\n (Type: {1}); (Message: {2})", message, aggrException.GetType(), aggrException.Message, aggrException.StackTrace));
        foreach (var ie in aggrException.InnerExceptions)
            LogException(ie, "Inner Exception.");
    }

    public static void LogException(Exception exception, string message)
    {
        Console.WriteLine(string.Format("{0}\n (Type: {1}); (Message: {2})", message, exception.GetType(), exception.Message, exception.StackTrace));
        if (exception.InnerException != null)
            LogException(exception.InnerException, "Inner Exception.");
    }

    public static void Main()
    {
        var invadidOpExcep1 = new InvalidOperationException("%INVALID_OP1%");
        LogException(invadidOpExcep1, "LOG1");
        Console.WriteLine("------------------------------------------------");
        var argumentExcep1 = new ArgumentException("%ARGUMENT1%");
        LogException(argumentExcep1, "LOG2");
        Console.WriteLine("------------------------------------------------");
        var aggregateExcep1 = new AggregateException("%AGGREGATE1%", invadidOpExcep1, argumentExcep1);
        LogException(aggregateExcep1, "LOG3");
        Console.WriteLine("------------------------------------------------");
        var indORExcep1 = new IndexOutOfRangeException("%INDOR1%");
        var aggregateExcep2 = new AggregateException("%AGGREGATE2%", aggregateExcep1, indORExcep1);
        LogException(aggregateExcep2, "LOG4");
    }
}

... 产生以下输出:

LOG1
 (Type: System.InvalidOperationException); (Message: %INVALID_OP1%)
------------------------------------------------
LOG2
 (Type: System.ArgumentException); (Message: %ARGUMENT1%)
------------------------------------------------
LOG3 Inner exceptions on following logs.
 (Type: System.AggregateException); (Message: %AGGREGATE1%)
Inner Exception.
 (Type: System.InvalidOperationException); (Message: %INVALID_OP1%)
Inner Exception.
 (Type: System.ArgumentException); (Message: %ARGUMENT1%)
------------------------------------------------
LOG4 Inner exceptions on following logs.
 (Type: System.AggregateException); (Message: %AGGREGATE2%)
Inner Exception.
 (Type: System.AggregateException); (Message: %AGGREGATE1%)
Inner Exception.
 (Type: System.InvalidOperationException); (Message: %INVALID_OP1%)
Inner Exception.
 (Type: System.IndexOutOfRangeException); (Message: %INDOR1%)

日志 1 到 3 很好。在前两个中,InvalidOperationExceptionArgumentException 都是Exceptions 并且不是AggregateExceptions,因此调用了带有ExceptionLogException。在第三个中,传递了一个AggregateException,因此调用了将该类型作为参数的重载。 但是在日志 4 上,传递了一个 AggregateException 有另一个 AggregateException 'inside',我预计它会调用 AggregateException 重载两次,这意味着,我预计第 4 个日志是:

LOG4 Inner exceptions on following logs.
 (Type: System.AggregateException); (Message: %AGGREGATE2%)
Inner Exception. Inner exceptions on following logs.
 (Type: System.AggregateException); (Message: %AGGREGATE1%)
Inner Exception.
 (Type: System.InvalidOperationException); (Message: %INVALID_OP1%)
Inner Exception.
 (Type: System.ArgumentException); (Message: %ARGUMENT1%)
Inner Exception.
 (Type: System.IndexOutOfRangeException); (Message: %INDOR1%)

谁能解释一下这里发生了什么?

提前致谢。

【问题讨论】:

  • 根据编译时类型调用方法。您似乎实际上想知道如何绕过该行为。见标记重复。或者,您可能会发现在foreach 循环中创建ie 的类型dynamic 也会产生您想要的效果。
  • '有趣'事实上,如果我在 .NET Core(至少 3.1)上运行它,我就不需要这个代码,因为 AggregateException.Message 已经包含了它的所有 InnerExceptions'消息。

标签: c# recursion overloading


【解决方案1】:

AggregateException.InnerExceptions 的类型为 System.Collections.ObjectModel.ReadOnlyCollection<Exception>。这意味着您的 foreach 变量 ie 的类型为 Exception。因为LogException 的调用是静态调度的(在编译时),所以编译器会选择带有Exception 签名的重载。

【讨论】:

  • 这就是为什么我强烈建议明确指定变量类型,并且永远不要使用 var 关键字。
  • 直到现在,我一直认为var更好,因为它“更干净”。但是,是的,我想我必须停止使用它。非常感谢!
【解决方案2】:

方法调用在编译时解决。在日志 4 上,您传递了一个 AggregateException,正如您所料,LogException(AggregateException, string) 被调用。

然后,在调用InnerException 的结果上调用LogExceptionInnerException 返回一个Exception,所以LogException(Exception, string) 被调用。实际返回的运行时类型无关紧要,因为解析是在编译时完成的。

【讨论】:

  • 感谢您的回答。如果伊曼纽尔没有先回答,我会接受你的回答。
猜你喜欢
  • 2014-07-25
  • 1970-01-01
  • 2014-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-07
  • 1970-01-01
相关资源
最近更新 更多