Pergunta

É possível definir uma classe em C # tal que

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

Eu poderia não para a vida de mim realizar esta última noite em .NET 3.5. Eu tentei usar

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

Parece-me que este deve ser permitido de alguma forma. Eu estou tentando implementar meu próprio EventQueue.

I terminou apenas fazendo isso [aproximação mente primitiva você].

internal delegate void DWork();

class EventQueue {
    private Queue<DWork> eventq;
}

Mas então eu perder a capacidade de reutilizar a mesma definição para diferentes tipos de funções.

Os pensamentos?

Foi útil?

Solução

Um número de classes não estão disponíveis como genéricos contraints -. Enum ser outro

Para os delegados, o mais próximo que você pode obter é ": classe", talvez usando a reflexão para verificar (por exemplo, no construtor estático) que a T é um delegado:

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

Outras dicas

Editar: Algumas soluções alternativas propostas são propostas nestes artigos:

http://jacobcarpenters.blogspot.com/ 2006/06 / c-30-e-delegado-conversion.html

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


do C # 2.0 especificação podemos ler (20.7, Restrições):

A-tipo de classe restrição deve satisfazer as seguintes regras:

  • O tipo deve ser um tipo de classe.
  • O tipo não deve ser selado.
  • O tipo não deve ser um dos seguintes tipos:. System.Array, System.Delegate, System.Enum, ou System.ValueType
  • O tipo não deve ser objeto. Porque todos os tipos derivam do objeto, tal restrição não teria nenhum efeito se fosse permitido.
  • No máximo um constrangimento para um determinado tipo de parâmetro pode ser um tipo de classe.

E com certeza VS2008 cospe um erro:

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

Para informações e investigação sobre este assunto leia aqui .

Se você está disposto a assumir uma dependência em tempo de compilação em um IL Weaver que você pode fazer isso com Fody .

Usando este suplemento para Fody https://github.com/Fody/ExtraConstraints

Seu código pode parecer com isto

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

E ser compilado para este

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

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

Sim, é possível em C # 7.3, Restrições de família aumentou para incluir Enum, Delegate e tipos unmanaged. Você pode escrever o código sem um problema:

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

    }

Links úteis:

O futuro do C # , do Microsoft Build 2018

O que há de novo no C # 7.3?

Delegado já suporta encadeamento. Isso não atender às suas necessidades?

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
    }

}

me deparei com uma situação em que eu precisava lidar com uma Delegate internamente, mas eu queria uma restrição genérica. Especificamente, eu queria adicionar um manipulador de eventos usando a reflexão, mas eu queria usar um argumento genérico para o delegado. O código a seguir não funciona, uma vez que "Handler" é uma variável do tipo, eo compilador não rejeitará Handler para Delegate:

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

No entanto, você pode passar uma função que faz a conversão para você. convert leva um argumento Handler e retorna um Delegate:

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

Agora, o compilador é feliz. Chamar o método é fácil. Por exemplo, anexando ao evento KeyPress em um controle Windows Forms:

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

onde SomeControl_KeyPress é o destino do evento. A chave é o lambda conversor -. Não faz nenhum trabalho, mas convence o compilador que você deu um delegado válido

(Comece 280Z28) @Justin:? Por que não usar este

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

(Fim 280Z28)

Como mencionado acima, você não pode ter Delegados e Enum como uma restrição genérica. System.Object e System.ValueType também não pode ser usado como uma restrição genérica.

A em torno do trabalho pode ser se você construir uma chamada apropriada em você IL. Ele vai funcionar bem.

Aqui está um bom exemplo por Jon Skeet.

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

Tomei minhas referências do livro de Jon Skeet C # in Depth , 3ª edição.

De acordo com a MSDN

Compiler erro CS0702

restrição não pode ser classe 'identificador' especial os seguintes tipos não podem ser utilizados como restrições:

  • System.Object
  • System.Array
  • System.Delegate
  • System.Enum
  • System.ValueType.
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top