C# Generics не разрешает ограничения типа делегата
можно ли определить класс В C# такой, что
class GenericCollection<T> : SomeBaseCollection<T> where T : Delegate
Я не мог для жизни меня выполнить это прошлой ночью в .NET 3.5. Я пробовал использовать
delegate, Delegate, Action<T> and Func<T, T>
мне кажется, что это должно быть допустимым в некотором роде. Я пытаюсь реализовать свой собственный EventQueue.
Я закончил тем, что просто делал это [примитивное приближение, заметьте].
internal delegate void DWork();
class EventQueue {
private Queue<DWork> eventq;
}
но тогда я потеряю возможность использовать одно и то же определение для различных тип функции.
мысли?
8 ответов:
ряд классов недоступны в качестве общих противопоказаний-перечисление является другим.
для делегатов самое близкое, что вы можете получить, это": class", возможно, используя отражение, чтобы проверить (например, в статическом конструкторе), что T и делегат:
static GenericCollection() { if (!typeof(T).IsSubclassOf(typeof(Delegate))) { throw new InvalidOperationException(typeof(T).Name + " is not a delegate type"); } }
Edit: некоторые предлагаемые обходные пути предлагаются в этих статьях:
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, ограничения):
ограничение типа класса должно удовлетворять следующим требованиям правила:
- тип должен быть типом класса.
- тип не должен быть запечатан.
- тип не должен быть одним из следующих типов: System.Массив, Система.Делегат, Система.Перечисление, или система.ValueType.
- тип не должен быть object. Поскольку все типы являются производными от объекта, такое ограничение не будет иметь никакого эффекта, если оно будет разрешено.
- не более одного ограничения для данного параметра типа может быть класс тип.
и конечно же VS2008 выплевывает ошибку:
error CS0702: Constraint cannot be special class 'System.Delegate'
для получения информации и расследования по этому вопросу читайте здесь.
Если вы хотите взять зависимость времени компиляции от IL Weaver, вы можете сделать это с помощью Фоды.
используя это дополнение к 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<T>() where T: Delegate { } public void MethodWithEnumConstraint<T>() 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<int> myAction = x => Console.WriteLine("foo {0}", x); myAction += x => Console.WriteLine("bar {0}", x); myAction(3); //foo 3 //bar 3 } public void Test3() { Func<int, int> 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<int, int> myFunc = x => { Console.WriteLine("foo {0}", x); return x + 2; }; Func<int, int> 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
внутренне, но я хотел общее ограничение. В частности, я хотел добавить обработчик событий с помощью отражения, но я хотел использовать общий аргумент для делегата. Приведенный ниже код не работает, так как "обработчик" является переменной типа, и компилятор не будет приводитьHandler
доDelegate
:public void AddHandler<Handler>(Control c, string eventName, Handler d) { c.GetType().GetEvent(eventName).AddEventHandler(c, (Delegate) d); }
тем не менее, вы можете передать функцию, которая выполняет преобразование для вас.
convert
принимает
Да это возможно в C# 7.3, ограничения семьи увеличены, чтобы включить
Enum
,Delegate
иunmanaged
типы. Вы можете написать этот код без проблем:void M<D, E, T>(D d, E e, T* t) where D : Delegate where E : Enum where T : unmanaged { }
Полезные ссылки:
будущее C#, от Microsoft Build 2018
Как упоминалось выше, вы не можете иметь делегаты и перечисление в качестве общего ограничения.
System.Object
иSystem.ValueType
также не может использоваться в качестве общего ограничения.работа вокруг может быть, если вы создадите соответствующий вызов в вас IL. Он будет работать нормально.
вот хороший пример Джона Скита.
http://code.google.com/p/unconstrained-melody/
Я взял свои рекомендации из книги Джона Скита C# в глубину, 3-е издание.
по данным MSDN
ошибка компилятора CS0702
ограничение не может быть специальным идентификатором класса следующие типы не могут использоваться в качестве ограничений: