Как привести значение int к эквивалентному параметру универсального типа, например char?

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

Я создаю связанный список. Я хочу, чтобы он хранил значения char или int. Поэтому я решил сделать реализацию универсальной:

public class Node<T> where T : struct, IConvertible
{
    public Node<T> next = null;
    public T data = default(T);

    public Node(T value) { this.data = value; }
}

У меня есть метод, который создает связанный список, генерируя случайные значения в диапазоне [33,127], преобразовывая значение в тип, указанный T (например, если генерируется 86, а T - Char, то значение, которое будет сохранено в связанном списке node будет 'V'; если T - Int32, тогда значение будет просто 86). Я сталкиваюсь с двумя проблемами:

    static Node<IConvertible> CreateList<T>(int len) where T : struct, IConvertible
    {
        Random r = new Random((int)DateTime.Now.Ticks);
        T value = (T)r.Next(33, 127);       // Problem #1

        Node<T> head = new Node<T>(value);
        Node<T> n = head;

        for (int i = 1; i < len; i++)
        {
            n.next = new Node<T>(value);
            n = n.next;
        }
        return head;  // Problem #2
    }

Это проблемы:

1) Обычно это возможно: (int) value = (char) r.Next(33, 127). Почему, если T имеет тип Char, компилятор говорит: «Невозможно преобразовать тип 'int' в 'T'», даже если я указал «где T: struct, IConvertible»?

2) «Невозможно неявно преобразовать тип 'LinkedList.Node<T>' в 'LinkedList.Node<System.IConvertible>'». Если T является либо Int32, либо Char, и оба они реализуют IConvertible, как преобразовать Node<Int32> или Node<Char> в Node<IConvertible>?

Большое спасибо!


person user1730118    schedule 23.11.2012    source источник


Ответы (3)


Проблема в том, что T может быть любой структурой, например. Guid, SByte... или новый пользовательский. и хотя мы можем быть уверены, что T — это struct и IConvertible, нет необходимости использовать явный оператор приведения для

public static explicit operator AnyStruct(int i)

Вторая проблема приведения Node<System.IConvertible> к Node<System.IConvertible> обычная. Любой список List<T> нельзя преобразовать в List<System.IConvertible>.

Что нам нужно, так это объявление ковариации на интерфейсе: INode<out T>. Тогда INode<T> можно преобразовать в INode<System.IConvertible>

person Radim Köhler    schedule 23.11.2012

Ваше использование Random для генерации некоторых данных противоречит использованию дженериков. Я бы разделил их так:

static Node<T> CreateList<T>(int len, Func<T> dataProvider) where T : struct, IConvertible
{   
    Node<T> head = new Node<T>(dataProvider());
    Node<T> n = head;

    for (int i = 1; i < len; i++)
    {
        n.next = new Node<T>(dataProvider());
        n = n.next;
    }
    return head;
}

код вызова:

Random r = new Random();
Node<char> list = CreateList(10, () => (char)r.Next(33, 127));

Вторая проблема заключается в том, что Node<IConvertible> не разрешено вашим ограничением struct на Node<T>. Просто верните Node<T>. Даже если вы уберете ограничение struct из Node<T>, будет невозможно вернуть Node<IConvertible>, потому что универсальные классы не поддерживают дисперсию.

person Mike Zboray    schedule 23.11.2012

Использовать

T value = (T)Convert.ChangeType(r.Next(33, 127), typeof(T));
person Kirill Bestemyanov    schedule 23.11.2012