C # Generics does not allow delegate type restrictions

Is it possible to define a class in C # so that

class GenericCollection<T> : SomeBaseCollection<T> where T : Delegate 

I could not fulfill this last night in .NET 3.5 in my life. I tried to use

delegate, Delegate, Action<T> and Func<T, T>

It seems to me that this should be acceptable in some way. I am trying to implement my own EventQueue.

In the end, I just did this [primitive approximation of the mind].

 internal delegate void DWork(); class EventQueue { private Queue<DWork> eventq; } 

But then I lose the ability to reuse the same definition for different types of functions.

Thoughts?

+66
generics c # events delegates constraints
Oct. 10 '08 at 15:42
source share
7 answers

Several classes are not available as general contraindications - Enum is different.

For delegates, the closest to you might be ": class", possibly using reflection to verify (for example, in a static constructor) that T is a delegate:

  static GenericCollection() { if (!typeof(T).IsSubclassOf(typeof(Delegate))) { throw new InvalidOperationException(typeof(T).Name + " is not a delegate type"); } } 
+60
Oct 10 '08 at 15:44
source share

Edit: Some proposed work options are offered in the following articles:

http://jacobcarpenters.blogspot.com/2006/06/c-30-and-delegate-conversion.html

http://jacobcarpenters.blogspot.com/2006_11_01_archive.html




From the C # 2.0 specification we can read (20.7, Constraints):

A class type constraint must satisfy the following rules:

  • The type must be a class type.
  • Type must not be closed.
  • The type must not be one of the following types: System.Array, System.Delegate, System.Enum, or System.ValueType .
  • The type should not be an object. Since all types are descended from an object, such a restriction will have no effect if it were allowed.
  • At most one restriction for a given type parameter can be a class type.

And, of course, VS2008 spits out an error:

 error CS0702: Constraint cannot be special class 'System.Delegate' 

For information and research on this issue, read here .

+13
Oct 10 '08 at 15:52
source share

If you are ready to take the compile-time dependency on IL Weaver, you can do this with Fody .

Using this addin for Fody https://github.com/Fody/ExtraConstraints

Your code might look like this

 public class Sample { public void MethodWithDelegateConstraint<[DelegateConstraint] T> () { } public void MethodWithEnumConstraint<[EnumConstraint] T>() { } } 

And compile this

 public class Sample { public void MethodWithDelegateConstraint<T>() where T: Delegate { } public void MethodWithEnumConstraint<T>() where T: struct, Enum { } } 
+10
Jun 01 2018-12-12T00:
source share

The delegate already supports the chain. Doesn't that fit your needs?

 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 } } 
+3
Oct 10 '08 at 18:20
source share

I came across a situation where I needed to deal with Delegate internally, but I needed a general constraint. In particular, I wanted to add an event handler using reflection, but I wanted to use a common argument for the delegate. The code below does NOT work, since the "Handler" is a type variable, and the compiler will not distinguish Handler until Delegate :

 public void AddHandler<Handler>(Control c, string eventName, Handler d) { c.GetType().GetEvent(eventName).AddEventHandler(c, (Delegate) d); } 

However, you can pass a function that performs the conversion for you. convert takes a Handler argument and returns a Delegate :

 public void AddHandler<Handler>(Control c, string eventName, Func<Delegate, Handler> convert, Handler d) { c.GetType().GetEvent(eventName).AddEventHandler(c, convert(d)); } 

Now the compiler is happy. The method call is simple. For example, attaching to a KeyPress event in a Windows Forms control:

 AddHandler<KeyEventHandler>(someControl, "KeyPress", (h) => (KeyEventHandler) h, SomeControl_KeyPress); 

where SomeControl_KeyPress is the purpose of the event. The key is the lambda converter - it does not work, but it convinces the compiler that you gave it a valid delegate.

(Start 280Z28) @Justin: Why not use this?

 public void AddHandler<Handler>(Control c, string eventName, Handler d) { c.GetType().GetEvent(eventName).AddEventHandler(c, d as Delegate); } 

(end 280Z28)

+3
Jan 18 '10 at 18:30
source share

As mentioned above, you cannot have delegation and Enum as a general limitation. System.Object and System.ValueType also cannot be used as a common limitation.

Work around can be if you build the corresponding call in IL. It will work fine.

Here is a good example: John Skeet.

http://code.google.com/p/unconstrained-melody/

I took my recommendations from John Skeet's C # book in Dept 3.

+2
May 19 '14 at 2:22
source share

According to MSDN

Compiler Error CS0702

A constraint cannot be a special class identifier. The following types cannot be used as limitations:

  • System.object
  • System.Array
  • System.Delegate
  • System.enum
  • System.ValueType.
+1
Apr 30 '15 at 8:21
source share



All Articles