Проблема
Это то, с чем я столкнулся некоторое время назад и смог как-то обойти это.Но теперь он вернулся, питаясь моим любопытством - и я бы хотел получить определенный ответ.
По сути, у меня есть универсальный dgv BaseGridView<T> : DataGridView where T : class
.Построенные типы, основанные на BaseGridView
(например, InvoiceGridView : BaseGridView<Invoice>
), позже используются в приложении для отображения различных бизнес-объектов с использованием общей функциональности, предоставляемой BaseGridView
(например, виртуальный режим, кнопки и т. Д.).
Теперь стало необходимо создать пользовательский элемент управления, который ссылается на эти сконструированные типы, чтобы управлять некоторыми из функций shared (например, фильтрация) из BaseGridView
.Поэтому я надеялся создать в пользовательском элементе управления открытое свойство, которое позволило бы мне присоединить его к любому BaseGridView
в Designer / code: public BaseGridView<T> MyGridView { get; set; }
.Проблема в том, что это не работает :-) При компиляции я получаю следующее сообщение:
Не удалось найти тип или имя пространства имен 'T' (вы пропустили директиву using илиссылка на сборку?)
Решения?
Я понимаю, что могу извлечь общую функциональность для интерфейса, пометить BaseGridView
как реализацию этого интерфейса и затем обратиться к созданному интерфейсупод моим контролем.
Но мне любопытно, существует ли какая-то таинственная команда / синтаксис 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' должен быть противоположно допустимым для 'GeParts.Controls.IBaseGridView.ScrollTo (T)'.'T' является ковариантным.
Теперь мне нужно изменить подпись на ScrollTo(object o)
- что не идеально, но выполняет свою работу.Что меня удивило, так это то, что компилятор пожаловался на второй ScrollTo
, но был доволен первым.Таким образом, кажется, что нельзя передавать экземпляров из out T
, но использование самого типа (например, в Predicate<T>
) нормально?Кажется довольно придирчивым ...