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

#c# #.net #generics

Вопрос:

Учитывая универсальный класс Foo<T> с методом public T Convert(string value) , я пытаюсь обработать возможность, которая T определена как массив.

Например, T как простой тип:

 Foo<int> foo = new Foo<int>();
int bar = foo.Convert("123");
// bar == 123
 

Но также T и в виде массива:

 Foo<int[]> foo = new Foo<int[]>();
int[] bars = foo.Convert("1,2,3");
// bars = [1, 2, 3]
 

Вот класс Foo с недопустимым приведением, которое я не совсем уверен, как решить.

 public class Foo<T>
{

    public T Convert(string value)
    {
        Type t = typeof(T);
        if (t.IsArray)
        {
            string[] values = value.Split(',');
            Type elementType = t.GetElementType();
            // this cast is invalid
            return (T)values.Select(v => elementType.IsEnum ? Enum.Parse(elementType, v, true) : ChangeType(v, elementType)).ToArray();
        }
        else
        {
            return (T)ChangeType(value, t);
        }
    }

    private object ChangeType(string value, Type type)
    {
        if (type.IsGenericType amp;amp; type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
        {
            if (value == null)
            {
                return defau<
            }
            type = Nullable.GetUnderlyingType(type);
        }
        return System.Convert.ChangeType(value, type);
    }

}
 

Комментарии:

1. В строке недопустимого приведения… Вам нужно использовать его как T или T[] ?

Ответ №1:

На самом деле вы здесь не используете функции дженериков, за исключением получения типа с помощью typeof(T). Таким образом, решение без дженериков было бы:

 public class Foo
{
    public object Convert(string value, Type t)
    {
        if (t.IsArray)
        {
            string[] values = value.Split(',');
            Type elementType = t.GetElementType();
            var array = Array.CreateInstance(elementType, values.Length);
            for (var i = 0; i < values.Length; i  )
            {
                array.SetValue(elementType.IsEnum ? Enum.Parse(elementType, values[i], true) : ChangeType(values[i], elementType), i);
            }
            return array;
        }
        else
        {
            return ChangeType(value, t);
        }
    }

    private object ChangeType(string value, Type type)
    {
        if (type.IsGenericType amp;amp; type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
        {
            if (value == null)
            {
                return defau<
            }
            type = Nullable.GetUnderlyingType(type);
        }
        return System.Convert.ChangeType(value, type);
    }
}
 

Обратите внимание, что я использую Array.CreateInstance , например, для создания правильного int[] вместо object[] созданного вами values.Select(v => elementType.IsEnum ? Enum.Parse(elementType, v, true) : ChangeType(v, elementType)).ToArray() .

Если вы хотите, вы все равно можете иметь универсальную версию поверх нее:

 public class Foo<T> : Foo
{
    public T Convert(string value)
    {
        return (T)Convert(value, typeof(T));
    }
}
 

Комментарии:

1. Именно то, что я искал, спасибо! Я обходил это стороной весь день. Я попытался сделать это с Массивом. Создайте объект, и почему-то я просто упустил, что его можно было бы отлить как объект, а затем Т. Очень высоко оценил.

Ответ №2:

Почему бы не сохранить свой impl, который понимает Foo<int> , и не использовать его для создания массива:

 int[] bars = "1,2,3".Split(",").Select(foo.Convert).ToArray();
 

Таким образом, вызывающий метод может быть тем, кто знает, как устроен массив, а не преобразовывать его в формат CSV:

 int[] bars = "1-2-3".Split("-").Select(foo.Convert).ToArray();
 

Мне действительно интересно, что вы на самом деле выигрываете от обмена фу.Однако конвертируйте для внутреннего анализа.. Похоже, вы пишете большой, запутанный, медленный мега-анализатор для небольшой выгоды, предлагая метод статического анализа для вашего пользовательского типа и вызывая его в соответствии с вышеизложенным