Создание объекта с использованием деревьев выражений без общих c аргументов - PullRequest
0 голосов
/ 18 июня 2020

У меня есть класс, который немного похож на следующий

public class SpecialList<T> : List<T>
{
    public SingleOrList() { }
    public SingleOrList(IEnumerable<T> list) : base(list) {}
    ...
}

При преобразовании его из JSON он может быть превращен в этот специальный список либо как отдельный объект, либо как массив этого объект следующим образом.

...

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    var token = JToken.Load(reader);

    if (token.Type == JTokenType.Array)
    {
        var originalList = token.ToObject(objectType.BaseType, serializer);
        return Activator.CreateInstance(objectType, originalList);
    }

    var list = (IList) Activator.CreateInstance(objectType);
    var genericType = objectType.GetGenericArguments().Single();
    var single = token.ToObject(genericType, serializer);

    list.Add(single);

    return list;
}

Игнорируя тот факт, является ли это хорошей идеей на данный момент, меня интересовало, можете ли вы использовать / как использовать здесь согласованные деревья выражений вместо Activator.CreateInstance для создания классов.

В большинстве примеров, которые я видел, используются дженерики, которые для меня здесь невозможны, поскольку я не знаю заранее тип generi c, например

public static Func<T> Instance = Expression.Lambda<Func<T>>(Expression.New(typeof(T))).Compile();

На основе комментария canton7, где TypeCreators - это некая форма кеша:

private static IList CreateForType(Type objectType)
{
    if (TypeCreators.TryGetValue(objectType, out var func))
    {
        return func();
    }

    var newFunc = Expression.Lambda<Func<IList>>(Expression.New(objectType)).Compile();
    TypeCreators.TryAdd(objectType, newFunc);
    return newFunc();
}
...