Я работаю над произвольным преобразованием дерева объектов в какой-то определенный формат, используя динамическую диспетчеризацию (чтобы упростить обработку обобщений).Дерево объектов генерируется кодом взаимодействия, упаковывает некоторые значения в контейнеры, для которых определены неявные преобразования.
Когда я обрабатываю эти контейнеры, я нажимаю StackOverflowException
.Сначала я подумал, что, возможно, есть глупая ошибка, когда я просто вызываю Accept
с тем же значением, однако мне удалось сузить мою проблему до следующего:
using System;
using System.Runtime.CompilerServices;
class Program {
static void Main(string[] args) {
var container = new Container<object>("42");
Accept((dynamic)container);
}
static void Accept(object obj) { Console.WriteLine(nameof(obj)); }
static void Accept(int i32) { Console.WriteLine(nameof(i32)); }
static void Accept<T>(IContainer<T> container) {
RuntimeHelpers.EnsureSufficientExecutionStack();
Accept((dynamic)container.Get());
}
}
public interface IContainer<out T>{
T Get();
}
public struct Container<T>: IContainer<object> {
readonly T value;
public Container(T value){ this.value = value; }
public static implicit operator Container<T>(T value) => new Container<T>(value);
public object Get() => this.value;
}
Удивительно, но EnsureSufficientExecutionStack
не удается,Очевидно, что все, что выполняет динамическую диспетчеризацию для значения container.Get()
, оборачивает результат обратно в Container<object>
и передает результат в Accept<T>(IContainer<T>)
вместо передачи его непосредственно Accept(object)
.
Вопрос: чтологика следует, когда он решит это сделать?Это имело небольшой смысл, когда у меня был Accept<T>(Container<T>)
, поскольку я мог видеть, что он может вызывать неявное преобразование, но я не могу понять, как он даже находит неявное преобразование в какую-то произвольную реализацию интерфейса для отправки в перегрузку с интерфейсомпараметр.
Что поразило меня полностью, так это то, что если в Container<object>? container = new Container<object>("42");
я заменю object
на string
, ошибка исчезнет, и программа правильно напечатает obj