Возможно ли сделать upcast делегата Func?
Упрощенный абстрактный пример. Есть ExceptionMapper
, который должен уметь настраивать маппинг SomeException -> SomeObj
и конвертировать объект типа SomeException
в JSON строку, представленную в виде объекта SomeObject
. Код консольного приложения (.net-8) ниже.
Основная проблема - хранить маппинг для определенного Exception
. Маппинг представлен делегатом
Func<T, TObj> mapFn where T: Exception where TObj: class
. Я объявил словарь:
private static Dictionary<string, Func<Exception, object>> _map = new();
Казалось бы, что тип Exception
шире, чем любой из возможных <T> where T: Exception
. Также и object
будет шире любого типа <TObj> where TObj: class
, но такой upcast возвращает null:
public static void AddMapping<T, TObj>(Func<T, TObj> mapFn) where T: Exception where TObj: class
{
_map.Add(typeof(T).Name, mapFn as Func<Exception, object>); // <-- Тут upcast возвращает null
}
Вопросы:
- Почему такой upcast не срабатывает как ожидается?
- Как изменить мой пример, чтобы ожидаемое поведение работало?
Полный код (можно вставить в Program.cs консольного приложения и запускать):
using System.Text.Json;
ExceptionMapper.AddMapping((ApplicationException ex) => new { Message = ex.Message });
var result = ExceptionMapper.MapToJson(new ApplicationException("App crushed"));
Console.WriteLine(result);
static class ExceptionMapper
{
private static Dictionary<string, Func<Exception, object>> _map = new();
public static void AddMapping<T, TObj>(Func<T, TObj> mapFn) where T: Exception where TObj: class
{
_map.Add(typeof(T).Name, mapFn as Func<Exception, object>); // <-- Тут upcast возвращает null
}
public static string MapToJson<T>(T ex) where T : Exception
{
if (!_map.TryGetValue(ex.GetType().Name, out var mapFn))
{
return JsonSerializer.Serialize(new {});
}
if (mapFn == null)
{
throw new Exception($"mapFn is null for mapped exception {ex.GetType().Name}"); // <-- Бросится exception
}
var obj = mapFn(ex);
return JsonSerializer.Serialize(obj);
}
}
Вывод в консоли:
Unhandled exception. System.Exception: mapFn is null for mapped exception ApplicationException