Как привести объект к универсальному возвращаемому типу, если возвращаемый тип является универсальным интерфейсом?

У меня есть поразительно уродливый метод, который должен извлекать разные данные из базы данных и использовать его для создания объекта запрошенного типа. Цель состоит в том, чтобы вытащить сортированное уродство в одно место, чтобы классы, происходящие от класса, содержащего этот метод, могли быть относительно чистыми.

У меня нет проблем с тем, когда он должен возвращать один объект, даже когда тип обнуляется:

protected T getValue<T>(ParameterObject myParameterObject)
{
    var typeOfT = typeof (T);

    if (typeOfT == typeof(bool))
    {
        string val = this.getValue(myParameterObject);

        if (val == null)
            return default(T);

        bool rVal;
        if (!Boolean.TryParse(val, out rVal))
            return default(T);

        return changeType<T>(rVal);
    }

    if (typeOfT == typeof (double?))
    {
        string val = this.getValue(myParameterObject);

        if (val == null)
            return default(T);

        double rVal;
        if (!Double.TryParse(val, out rVal))
            return default(T);

        return changeType<T>(rVal);
    }

    [...]
}

public static T changeType<T>(object value)
{
    var t = typeof(T);
    if (!t.IsGenericType || t.GetGenericTypeDefinition() != typeof(Nullable<>))
        return (T)Convert.ChangeType(value, t);

    if (value == null)
        return default(T);

    t = Nullable.GetUnderlyingType(t);
    return (T)Convert.ChangeType(value, t);
}

К сожалению, у меня есть случаи, когда мой желаемый тип возврата - IList, где я хочу вернуть список:

protected T getValue<T>(ParameterObject myParameterObject)
{
    var typeOfT = typeof (T);

    if (typeOfT.IsGenericType)
    {
        if (typeOfT.GetGenericTypeDefinition() == typeof (IList<>))
        {
            var genericArgumentType = typeOfT.GenericTypeArguments.FirstOrDefault();
            var baseType = typeof (List<>);
            var genericType = baseType.MakeGenericType(new[] {genericArgumentType});

            var rVal = Activator.CreateInstance(genericType);

            [code to populate the list] 

            return changeType<T>(rVal);
        }

    [...]
}

Я не могу вернуть rVal, потому что это объект, а не экземпляр T. Но моя функция changeType() завершается с ошибкой:

System.InvalidCastException: объект должен реализовывать IConvertible.

Итак, у меня есть универсальный метод, для которого тип возвращаемого значения - IList, и у меня есть объект, который является списком, но моя ссылка на него имеет тип Object. Как я могу привести его, чтобы я мог вернуть его из функции?

1 ответ

Ваш return (T)Convert.ChangeType(value, t); линия терпит неудачу, потому что ваш value объект не реализует IConvertible,

Из документов MSDN

[...] Чтобы преобразование прошло успешно, значение должно реализовывать интерфейс IConvertible, поскольку метод просто переносит вызов соответствующего метода IConvertible. Для этого метода требуется, чтобы преобразование значения в ConversionType поддерживалось.

Чтобы это исправить, я не уверен в общем, но для конкретного случая value существо IEnumerable или же IEnumerable<> типа, тогда вы можете попытаться разыграть, затем выполнить value.Select(x => changeType<ListGenT>(x)) запрос linq. Используя ваш changeType метод рекурсивно, это должно обрабатывать и вложенные универсальные типы.

Другие вопросы по тегам