C # Generics не допускает ограничений типа делегата
Можно ли определить class в C # так, чтобы
class GenericCollection : SomeBaseCollection where T : Delegate
Я не мог для жизни выполнить эту последнюю ночь в .NET 3.5. Я попытался использовать
delegate, Delegate, Action and Func
- Любопытно повторяющиеся шаблоны шаблонов и ограничений генериков (C #)
- Пружины в автоматическом макете: равномерно распределять представления с ограничениями в Xcode 5
- Общие ограничения, где T: struct и где T: class
- Используя дату в контрольном ограничении, Oracle
- Существует ли ограничение на C # для типов «реального числа»?
Мне кажется, что это должно быть допустимо каким-то образом. Я пытаюсь реализовать свой собственный EventQueue.
Я закончил тем, что сделал это [примитивное сближение ума].
internal delegate void DWork(); class EventQueue { private Queue eventq; }
Но тогда я теряю способность повторно использовать одно и то же определение для разных типов функций.
Мысли?
- Ограничить оси ggplot2 без удаления данных (внешние ограничения): увеличить
- Почему это обобщенное ограничение компилируется, когда оно, кажется, имеет круговую ссылку
- Ограничения на hibernate Ограничения И / ИЛИ комбинация
- Операция «Вставить, если не существует» в SQLite
- Есть ли ограничение, которое ограничивает мой общий метод численными типами?
- Есть ли общее ограничение, которое я мог бы использовать для оператора +?
- Использование переменной в предложении LIMIT в MySQL
- Как разрешить ввод только цифр в jTextField?
Ряд classов недоступен в качестве общих ограничений – Enum является другим.
Для делегатов наиболее близким вам может быть «: class», возможно, используя рефлексию для проверки (например, в статическом конструкторе), что T является делегатом:
static GenericCollection() { if (!typeof(T).IsSubclassOf(typeof(Delegate))) { throw new InvalidOperationException(typeof(T).Name + " is not a delegate type"); } }
Изменить: некоторые предлагаемые варианты работы предлагаются в следующих статьях:
http://jacobcarpenters.blogspot.com/2006/06/c-30-and-delegate-conversion.html
http://jacobcarpenters.blogspot.com/2006_11_01_archive.html
Из спецификации C # 2.0 мы можем прочитать (20.7, Constraints):
Ограничение типа classа должно удовлетворять следующим правилам:
- Тип должен быть типом classа.
- Тип не должен быть запечатан.
- Тип не должен быть одним из следующих типов: System.Array, System.Delegate, System.Enum или System.ValueType .
- Тип не должен быть объектом. Поскольку все типы происходят от объекта, такое ограничение не будет иметь никакого эффекта, если бы оно было разрешено.
- Не более одного ограничения для данного параметра типа может быть типом classа.
И, конечно же, VS2008 выплевывает ошибку:
error CS0702: Constraint cannot be special class 'System.Delegate'
Информацию и исследование по этой проблеме читайте здесь .
Если вы согласны принять зависимость времени компиляции от IL Weaver, вы можете сделать это с Fody .
Используя этот addin для Fody https://github.com/Fody/ExtraConstraints
Ваш код может выглядеть так:
public class Sample { public void MethodWithDelegateConstraint<[DelegateConstraint] T> () { } public void MethodWithEnumConstraint<[EnumConstraint] T>() { } }
И скомпилировать это
public class Sample { public void MethodWithDelegateConstraint() where T: Delegate { } public void MethodWithEnumConstraint () where T: struct, Enum { } }
Делегат уже поддерживает цепочку. Разве это не отвечает вашим потребностям?
public class EventQueueTests { public void Test1() { Action myAction = () => Console.WriteLine("foo"); myAction += () => Console.WriteLine("bar"); myAction(); //foo //bar } public void Test2() { Action myAction = x => Console.WriteLine("foo {0}", x); myAction += x => Console.WriteLine("bar {0}", x); myAction(3); //foo 3 //bar 3 } public void Test3() { Func myFunc = x => { Console.WriteLine("foo {0}", x); return x + 2; }; myFunc += x => { Console.WriteLine("bar {0}", x); return x + 1; }; int y = myFunc(3); Console.WriteLine(y); //foo 3 //bar 3 //4 } public void Test4() { Func myFunc = x => { Console.WriteLine("foo {0}", x); return x + 2; }; Func myNextFunc = x => { x = myFunc(x); Console.WriteLine("bar {0}", x); return x + 1; }; int y = myNextFunc(3); Console.WriteLine(y); //foo 3 //bar 5 //6 } }
Я столкнулся с ситуацией, когда мне нужно было иметь дело с Delegate
внутри страны, но я хотел получить общее ограничение. В частности, я хотел добавить обработчик событий, используя reflection, но я хотел использовать общий аргумент для делегата. Нижеприведенный код НЕ работает, поскольку «Handler» – это переменная типа, и компилятор не будет передавать Handler
для Delegate
:
public void AddHandler(Control c, string eventName, Handler d) { c.GetType().GetEvent(eventName).AddEventHandler(c, (Delegate) d); }
Однако вы можете передать функцию, которая выполняет преобразование для вас. convert
принимает аргумент Handler
и возвращает Delegate
:
public void AddHandler(Control c, string eventName, Func convert, Handler d) { c.GetType().GetEvent(eventName).AddEventHandler(c, convert(d)); }
Теперь компилятор счастлив. Вызов метода прост. Например, прикрепление к событию KeyPress
в элементе управления Windows Forms:
AddHandler(someControl, "KeyPress", (h) => (KeyEventHandler) h, SomeControl_KeyPress);
где SomeControl_KeyPress
– это цель события. Ключом является конвертер lambda – он не работает, но он убеждает компилятор, что вы дали ему действительный делегат.
(Начало 280Z28) @Justin: Почему бы не использовать это?
public void AddHandler(Control c, string eventName, Handler d) { c.GetType().GetEvent(eventName).AddEventHandler(c, d as Delegate); }
(Конец 280Z28)
Как уже упоминалось выше, у вас не может быть делегирование и Enum в качестве общего ограничения. System.Object
и System.ValueType
также не могут использоваться в качестве общего ограничения.
Работа вокруг может быть, если вы построите соответствующий звонок в IL. Он будет работать нормально.
Вот хороший пример Джона Скита.
http://code.google.com/p/unconstrained-melody/
Я взял мои рекомендации из книги Джона Скита C # в издании Dept 3.
Да, это возможно в C # 7.3, семейство Constraints увеличено, чтобы включить Enum
, Delegate
и unmanaged
типы. Вы можете написать этот код без проблем:
void M(D d, E e, T* t) where D : Delegate where E : Enum where T : unmanaged { }
Полезные ссылки:
Будущее C # , от Microsoft Build 2018
Что нового в C # 7.3?
Согласно MSDN
Ошибка компилятора CS0702
Ограничение не может быть специальным идентификатором classа. Следующие типы не могут использоваться в качестве ограничений:
- System.Object
- System.Array
- System.Delegate
- System.Enum
- System.ValueType.