Несозданные дженерики как свойства (например, Список <T>)

Проблема

Это - что-то, с чем я столкнулся некоторое время назад и смог работать вокруг этого так или иначе. Но теперь это возвратилось, питаясь моим любопытством - и я хотел бы иметь определенный ответ.

В основном у меня есть универсальный dgv BaseGridView<T> : DataGridView where T : class. Созданные типы на основе BaseGridView (такой как InvoiceGridView : BaseGridView<Invoice>) позже используются в приложении для отображения различных бизнес-объектов с помощью общей функциональности, обеспеченной BaseGridView (как виртуальный режим, кнопки, и т.д.).

Теперь стало необходимо создать пользовательский элемент управления, который ссылается на те созданные типы для управления частью общей функциональности (например, фильтрующий) от BaseGridView. Я поэтому надеялся создать общественную собственность на пользовательском элементе управления, который позволит мне присоединить ее к любому BaseGridView в Разработчике/коде: public BaseGridView<T> MyGridView { get; set; }. Проблема, она не работает :-) При компиляции я получаю следующее сообщение:

Тип или имя пространства имен 'T' не мог быть найден (Вы пропускаете директиву использования или ссылку на сборку?)

Решения?

Я понимаю, что мог извлечь общую функциональность к интерфейсу, метке BaseGridView как реализация, которые взаимодействуют через интерфейс и затем относятся к созданному интерфейсу в моем управлении uesr.

Но мне любопытно, если бы там существует некоторая тайная команда/синтаксис C#, которая помогла бы мне достигнуть того, что я хочу - не загрязняя мое решение интерфейсом, в котором я действительно не нуждаюсь :-)

Править: Для ссылки я действительно пробовал это невинное обходное решение: BaseGridView<object> MyGridView { get; set; }, и... это все еще не ответ: не Может неявно преобразовать вводят 'InvoiceGridView' к 'BaseGridView <объект>'.

Частичный успех (редактируют 2),

Хорошо, потому что ковариантность только поддерживается в интерфейсах, я допустил поражение и определил интерфейс (только показывающий часть его):

public interface IBaseGridView<out T> where T : class
{
    bool ScrollTo(Predicate<T> criteria);
    bool ScrollTo(T object);
}

Я теперь могу бросить своего возлюбленного InvoiceGridView к IBaseGridView<object> - который является потрясающим, и я - счастливый мальчик снова :-) Однако второе ScrollTo дает мне проблему после компиляции:

Недопустимое различие: параметр типа 'T' должен быть contravariantly допустимый на 'GeParts. Средства управления. IBaseGridView. ScrollTo (T)'. 'T' является ковариантным.

Я должен теперь изменить подпись к ScrollTo(object o) - который не идеален, но сделал задание. То, что удивило меня, было то, что компилятор жаловался на второе ScrollTo все же было довольно первым. Таким образом, кажется, что каждому не разрешают передать экземпляры out T, но с помощью самого типа (например, в Predicate<T>) прекрасен? Кажется довольно придирчивым...

1
задан John Saunders 18 June 2010 в 22:24
поделиться

5 ответов

Поскольку вы написали

Но я Мне любопытно, существует ли какая-то загадочная команда / синтаксис C #, которые помогли бы мне достичь того, чего я хочу

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

public BaseGridView < Object > MyGridView {get; установленный; }

Итак, вы получаете хорошо известный тип, но вы можете вернуть любой BaseGridView, какой захотите. К сожалению, единственная загвоздка в том, что ковариация разрешена только на интерфейсах! :(

1
ответ дан 2 September 2019 в 23:41
поделиться

Я просто попытался склеить какой-то код, и у меня он отлично работает:

    public class A<T> where T : class
    {
        public virtual A<T> ARef
        {
            get { return default(A<T>); }
        }
    }

    public class B : A<B>
    {
        public override A<B> ARef
        {
            get
            {
                return base.ARef;
            }
        }
    }
0
ответ дан 2 September 2019 в 23:41
поделиться

Насколько мне известно, C # не поддерживает общие свойства. Вы можете либо создать универсальные методы, либо сделать универсальный тип частью определения вашего класса.

Например:

public BaseGridView<T> GetMyGridView<T>() { ... }
public void SetMyGridView<T>(T gridView) { ... }

или

class MyClass<T> {
    public BaseGridView<T> MyGridView { get; set; }
}
1
ответ дан 2 September 2019 в 23:41
поделиться

Следующее, вероятно, сработает:

public BaseGridView<T> MyGridView<T> { get; set; }

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

Обратите внимание, что компилятор не может вывести универсальные типы из возвращаемых значений, поэтому вам потребуется указывать T при каждом вызове MyGridView .

0
ответ дан 2 September 2019 в 23:41
поделиться

Разве это не должно быть так:

public BaseGridView MyGridView {get; установленный; }

public BaseGridView<T> GetMyGridView<T> { return whatever; }
public void SetMyGridView<T>( BaseGridView<T> bgv) { whatever = bgv; }

??

Отредактировано. Мэтью прав, свойства не могут быть общими. Вам нужно будет использовать геттер / сеттер.

0
ответ дан 2 September 2019 в 23:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: