c# clases - C # Generics no permitirá restricciones de tipo de delegado





genericas debe (8)


Si está dispuesto a tomar una dependencia de tiempo de compilación en un IL Weaver, puede hacerlo con Fody .

Usando este complemento en Fody https://github.com/Fody/ExtraConstraints

Tu código puede verse así

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

Y compilarse para esto

public class Sample
{
    public void MethodWithDelegateConstraint<T>() where T: Delegate
    {
    }

    public void MethodWithEnumConstraint<T>() where T: struct, Enum
    {
    }
}

¿Es posible definir una clase en C # tal que

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

No podría, por mi vida, lograr esto anoche en .NET 3.5. Intenté usar

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

Me parece que esto debería ser permitido de alguna manera. Estoy tratando de implementar mi propio EventQueue.

Terminé haciendo esto [aproximación primitiva te importa].

internal delegate void DWork();

class EventQueue {
    private Queue<DWork> eventq;
}

Pero luego pierdo la capacidad de reutilizar la misma definición para diferentes tipos de funciones.

¿Pensamientos?




Como se mencionó anteriormente, no puede tener Delegados y Enum como una restricción genérica. System.Object y System.ValueType tampoco se pueden usar como una restricción genérica.

La solución puede ser si construyes una llamada apropiada en ti IL. Funcionará bien.

Este es un buen ejemplo de Jon Skeet.

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

He tomado mis referencias del libro de Jon Skeet C # en la edición del Depto. 3.




Sí, es posible en C # 7.3, la familia de restricciones aumenta para incluir Enum , Delegate y tipos unmanaged . Puedes escribir este código sin ningún problema:

void M<D, E, T>(D d, E e, T* t) where D : Delegate where E : Enum where T : unmanaged
    {

    }

Enlaces útiles:

El futuro de C # , de Microsoft Build 2018

¿Qué hay de nuevo en C # 7.3?




Me encontré con una situación en la que necesitaba tratar con un Delegate internamente, pero quería una restricción genérica. Específicamente, quería agregar un controlador de eventos utilizando la reflexión, pero quería usar un argumento genérico para el delegado. El código siguiente NO funciona, ya que "Handler" es una variable de tipo, y el compilador no lanzará Handler para Delegate :

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

Sin embargo, puede pasar una función que realice la conversión por usted. convert toma un argumento de Handler y devuelve un Delegate :

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

Ahora el compilador está feliz. Llamar al método es fácil. Por ejemplo, adjuntar al evento KeyPress en un control de Windows Forms:

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

donde SomeControl_KeyPress es el objetivo del evento. La clave es el convertidor lambda: no funciona, pero convence al compilador de que le otorgó un delegado válido.

(Comienza 280Z28) @Justin: ¿Por qué no usar esto?

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

(Fin 280Z28)




Varias clases no están disponibles como restricciones genéricas, siendo Enum otra.

Para los delegados, lo más cercano que puede obtener es ": clase", tal vez utilizando la reflexión para verificar (por ejemplo, en el constructor estático) que la T es un delegado:

static GenericCollection()
{
    if (!typeof(T).IsSubclassOf(typeof(Delegate)))
    {
        throw new InvalidOperationException(typeof(T).Name + " is not a delegate type");
    }
}



De acuerdo con MSDN

Error del compilador CS0702

La restricción no puede ser un 'identificador' de clase especial. Los siguientes tipos no se pueden usar como restricciones:

  • System.Object
  • System.Array
  • System.Delegate
  • System.Enum
  • System.ValueType.



Editar: Algunas propuestas de solución alternativa se proponen en estos artículos:

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

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

De la especificación C # 2.0 podemos leer (20.7, Restricciones):

Una restricción de tipo de clase debe cumplir las siguientes reglas:

  • El tipo debe ser un tipo de clase.
  • El tipo no debe ser sellado.
  • El tipo no debe ser uno de los siguientes tipos: System.Array, System.Delegate, System.Enum o System.ValueType .
  • El tipo no debe ser objeto. Como todos los tipos se derivan del objeto, tal restricción no tendría ningún efecto si estuviera permitida.
  • Como máximo, una restricción para un parámetro de tipo determinado puede ser un tipo de clase.

Y, por supuesto, VS2008 escupe un error:

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

Para información e investigación sobre este tema lea here .




Como se explica en otras respuestas, para usar este enfoque de tipo de ParameterizedType , necesita extender la clase, pero parece ser un trabajo extra para crear una clase completamente nueva que lo extienda ...

Entonces, al hacer que la clase sea abstracta, obliga a extenderla, satisfaciendo así el requisito de subclasificación. (usando @Getter de lombok).

@Getter
public abstract class ConfigurationDefinition<T> {

    private Class<T> type;
    ...

    public ConfigurationDefinition(...) {
        this.type = (Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];
        ...
    }
}

Ahora extenderlo sin definir una nueva clase. (Tenga en cuenta que {} al final ... extendido, pero no sobrescriba nada, a menos que quiera).

private ConfigurationDefinition<String> myConfigA = new ConfigurationDefinition<String>(...){};
private ConfigurationDefinition<File> myConfigB = new ConfigurationDefinition<File>(...){};
...
Class stringType = myConfigA.getType();
Class fileType = myConfigB.getType();




c# generics events delegates constraints