这个完整的C#程序说明了这个问题:
public abstract class Executor<T>
{
public abstract void Execute(T item);
}
class StringExecutor : Executor<string>
{
public void Execute(object item)
{
// why does this method call back into itself instead of binding
// to the more specific "string" overload.
this.Execute((string)item);
}
public override void Execute(string item) { }
}
class Program
{
static void Main(string[] args)
{
object item = "value";
new StringExecutor()
// stack overflow
.Execute(item);
}
}
Run Code Online (Sandbox Code Playgroud)
我遇到了一个StackOverlowException,我追溯到这个调用模式,我试图将调用转发给更具体的重载.令我惊讶的是,调用并没有选择更具体的重载,而是回调自身.它显然与基类型是通用的有关,但我不明白为什么它不会选择执行(字符串)重载.
有没有人对此有任何见解?
上面的代码被简化为显示模式,实际结构有点复杂,但问题是一样的.
这个问题再次引起了我的兴趣.有人可以提供技术解释,说明为什么以下代码不会产生任何警告或错误.你必须问自己的问题(当然)你感到幸运吗?
class Program
{
static string Feeling(object o) { return "Lucky"; }
static string Feeling(string s) { return "Unlucky"; }
static void Main(string[] args)
{
Console.WriteLine("I feel " + Feeling(null));
}
}
Run Code Online (Sandbox Code Playgroud)
如果您知道在不运行代码的情况下将调用哪种方法,则会获得奖励积分.只是为了添加侮辱,它不仅仅发生在null参数:
class Program
{
static string Feeling(int i) { return "Lucky"; }
static string Feeling(uint i) { return "Unlucky"; }
static void Main(string[] args)
{
Console.WriteLine("I feel " + Feeling(7));
}
}
Run Code Online (Sandbox Code Playgroud) 我最近发现了一个有趣的C#编译器行为.想象一下这样的界面:
public interface ILogger
{
void Info(string operation, string details = null);
void Info(string operation, object details = null);
}
Run Code Online (Sandbox Code Playgroud)
如果我们这样做
logger.Info("Create")
Run Code Online (Sandbox Code Playgroud)
编译器会抱怨他不知道选择哪个重载(不明确的调用......).似乎合乎逻辑,但是当你尝试这样做时:
logger.Info("Create", null)
Run Code Online (Sandbox Code Playgroud)
它突然没有麻烦,搞清楚null是一个字符串.此外,似乎找到正确的重载的行为已经随着时间的推移而改变,我发现旧代码中的错误在之前工作并且停止工作,因为编译器决定使用另一个重载.
所以我真的很想知道为什么C#在第二种情况下不会像第一种情况那样产生相同的错误.这样做似乎非常符合逻辑,但它尝试将其解析为随机重载.
PS我不认为提供这种模糊的界面是好的,不建议这样做,但遗产是遗留的,必须保持:)
我有这个服务接口。
public interface IService
{
Task SetAsync(string key, string value, TimeSpan? expiration = null);
Task SetAsync<T>(string applicationName, string key, T value, TimeSpan? expiration = null);
}
Run Code Online (Sandbox Code Playgroud)
我想通过这样做来调用第一种方法。
service.SetAsync("Key", "Value", TimeSpan.FromMinutes(1));
Run Code Online (Sandbox Code Playgroud)
方法调用与第一个方法的契约 100% 匹配。然而编译器通过假设TimeSpan是我的泛型类型来选择第二种方法。
为什么会这样?